[RFC PATCH v2 21/23] wpa_supplicant: Implement FTM peer measurement result handling

Peddolla Harshavardhan Reddy peddolla.reddy at oss.qualcomm.com
Thu Apr 2 05:24:26 PDT 2026


There is no mechanism to receive and process Fine Timing Measurement
(FTM) peer measurement results from the nl80211 driver in the proximity
ranging subsystem.

Add a new nl80211 event handler for NL80211_CMD_PEER_MEASUREMENT_RESULT
that parses the incoming netlink message and populates a new
peer_measurement_result structure, including all FTM-specific attributes.
Wire this up through the driver event interface and handle it in
wpa_supplicant by introducing wpas_pr_measurement_result(). Define two
new control interface events, PR_EVENT_PEER_MEASUREMENT for intermediate
per-burst results and PR_EVENT_PEER_MEASUREMENT_COMPLETE for the final
session result, carrying the peer address, status, and key FTM metrics
such as RTT and distance averages.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy at oss.qualcomm.com>
---
 src/common/wpa_ctrl.h              |   6 +
 src/drivers/driver.h               |  64 ++++++++
 src/drivers/driver_common.c        |   1 +
 src/drivers/driver_nl80211_event.c | 254 +++++++++++++++++++++++++++++
 wpa_supplicant/events.c            |   7 +
 wpa_supplicant/pr_supplicant.c     |  58 +++++++
 wpa_supplicant/pr_supplicant.h     |   8 +
 7 files changed, 398 insertions(+)

diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 963d30421..c7c61e6d1 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -480,6 +480,12 @@ extern "C" {
 /* Proximity Ranging parameters to use in ranging */
 #define PR_RANGING_PARAMS "PR-RANGING-PARAMS "
 
+/* Proximity Ranging measurement result */
+#define PR_EVENT_PEER_MEASUREMENT "PR-PEER-MEASUREMENT "
+
+/* Proximity Ranging measurement complete */
+#define PR_EVENT_PEER_MEASUREMENT_COMPLETE "PR-PEER-MEASUREMENT-COMPLETE "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index c250bdaa9..8ccc0d6f0 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -6381,6 +6381,14 @@ enum wpa_event_type {
 	 */
 	EVENT_SETUP_LINK_RECONFIG,
 
+	/**
+	 * EVENT_PEER_MEASUREMENT_RESULT - Ranging measurement result
+	 *
+	 * The driver uses this event to indicate completion of a ranging
+	 * measurement.
+	 */
+	EVENT_PEER_MEASUREMENT_RESULT,
+
 	/**
 	 * EVENT_NAN_CLUSTER_JOIN - Notification of a new cluster having been
 	 * joined or started.
@@ -7432,6 +7440,62 @@ union wpa_event_data {
 		u32 chan_bw_interference_bitmap;
 		int link_id;
 	} incumbt_sig_intf_event;
+
+	/**
+	 * struct peer_measurement_result - Ranging measurement result
+	 */
+	struct peer_measurement_result {
+		u8 addr[ETH_ALEN];
+		u32 status;
+		u64 host_time;
+		u64 ap_tsf;
+		u8 final;
+		u64 cookie;
+
+		/**
+		 * struct peer_measurement_ftm_result -
+		 * FTM-specific measurement results
+		 */
+		struct peer_measurement_ftm_result {
+			u8 fail;
+			u32 burst_index;
+			u32 num_ftmr_attempts;
+			u32 num_ftmr_successes;
+			u32 busy_retry_time;
+			u32 num_bursts_exp;
+			u32 burst_duration;
+			u32 ftms_per_burst;
+			s32 rssi_avg;
+			s32 rssi_spread;
+			s64 rtt_avg;
+			u64 rtt_variance;
+			u64 rtt_spread;
+			s64 dist_avg;
+			u64 dist_variance;
+			u64 dist_spread;
+			const u8 *lci;
+			size_t lci_len;
+			const u8 *civicloc;
+			size_t civicloc_len;
+			/* Additional FTM parameters */
+			u32 burst_period;
+			u32 tx_ltf_repetition_count;
+			u32 rx_ltf_repetition_count;
+			u32 max_time_between_measurements;
+			u32 min_time_between_measurements;
+			u32 num_tx_spatial_streams;
+			u32 num_rx_spatial_streams;
+			u16 nominal_time;
+			u8 availability_window;
+			u8 measurements_per_aw;
+			u32 band_width;
+			u32 preamble;
+			u8 is_delayed_lmr;
+			/* Flag indicating if FTM data is present */
+			u8 has_data;
+		} ftm;
+
+	} peer_measurement_result;
 };
 
 /**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 50a0b682d..f41d6fad3 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -102,6 +102,7 @@ const char * event_to_string(enum wpa_event_type event)
 	E2S(LINK_RECONFIG);
 	E2S(MLD_INTERFACE_FREED);
 	E2S(SETUP_LINK_RECONFIG);
+	E2S(PEER_MEASUREMENT_RESULT);
 	E2S(NAN_CLUSTER_JOIN);
 	E2S(NAN_NEXT_DW);
 	E2S(INCUMBT_SIG_INTF_DETECTED);
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index d71b06d5f..bed4b57a8 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -4083,6 +4083,255 @@ static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
 		   MAC2STR((u8 *) nla_data(mac)), nla_get_u32(timeout));
 }
 
+#ifdef CONFIG_PR
+
+static void
+nl80211_parse_peer_ftm_result(struct peer_measurement_ftm_result *ftm,
+			      struct nlattr *ftm_data)
+{
+	struct nlattr *ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1];
+
+	if (nla_parse_nested(ftm_tb, NL80211_PMSR_FTM_RESP_ATTR_MAX,
+			     ftm_data, NULL))
+		return;
+
+	ftm->has_data = 1;
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) {
+		ftm->fail = 1;
+		wpa_printf(MSG_ERROR,
+			   "nl80211: Ranging has failed with status %u",
+			    nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]));
+		return;
+	}
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX])
+		ftm->burst_index =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS])
+		ftm->num_ftmr_attempts =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES])
+		ftm->num_ftmr_successes =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME])
+		ftm->busy_retry_time =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP])
+		ftm->num_bursts_exp =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION])
+		ftm->burst_duration =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST])
+		ftm->ftms_per_burst =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG])
+		ftm->rssi_avg =
+			nla_get_s32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD])
+		ftm->rssi_spread =
+			nla_get_s32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG])
+		ftm->rtt_avg =
+			nla_get_s64(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE])
+		ftm->rtt_variance =
+			nla_get_u64(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD])
+		ftm->rtt_spread =
+			nla_get_u64(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG])
+		ftm->dist_avg =
+			nla_get_s64(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE])
+		ftm->dist_variance =
+			nla_get_u64(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD])
+		ftm->dist_spread =
+			nla_get_u64(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]) {
+		ftm->lci = nla_data(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]);
+		ftm->lci_len = nla_len(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]);
+	}
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]) {
+		ftm->civicloc =
+			nla_data(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]);
+		ftm->civicloc_len =
+			nla_len(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]);
+	}
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_PERIOD])
+		ftm->burst_period =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_PERIOD]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_TX_LTF_REPETITION_COUNT])
+		ftm->tx_ltf_repetition_count =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_TX_LTF_REPETITION_COUNT]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RX_LTF_REPETITION_COUNT])
+		ftm->rx_ltf_repetition_count =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_RX_LTF_REPETITION_COUNT]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MAX_TIME_BETWEEN_MEASUREMENTS])
+		ftm->max_time_between_measurements =
+		nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MAX_TIME_BETWEEN_MEASUREMENTS]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS])
+		ftm->min_time_between_measurements =
+		nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_TX_SPATIAL_STREAMS])
+		ftm->num_tx_spatial_streams =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_TX_SPATIAL_STREAMS]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_RX_SPATIAL_STREAMS])
+		ftm->num_rx_spatial_streams =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_RX_SPATIAL_STREAMS]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NOMINAL_TIME])
+		ftm->nominal_time =
+			nla_get_u16(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_NOMINAL_TIME]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_AVAILABILITY_WINDOW])
+		ftm->availability_window =
+			nla_get_u8(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_AVAILABILITY_WINDOW]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MEASUREMENTS_PER_AW])
+		ftm->measurements_per_aw =
+			nla_get_u8(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_MEASUREMENTS_PER_AW]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_CHANNEL_WIDTH])
+		ftm->band_width =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_CHANNEL_WIDTH]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_PREAMBLE])
+		ftm->preamble =
+			nla_get_u32(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_PREAMBLE]);
+
+	if (ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_IS_DELAYED_LMR])
+		ftm->is_delayed_lmr =
+			nla_get_flag(ftm_tb[NL80211_PMSR_FTM_RESP_ATTR_IS_DELAYED_LMR]);
+}
+
+
+static void nl80211_peer_measurement_result_event(struct i802_bss *bss,
+						  struct nlattr **tb)
+{
+	union wpa_event_data data;
+	struct nlattr *pmsr[NL80211_PMSR_ATTR_MAX + 1];
+	struct nlattr *peer;
+	u64 cookie = 0;
+	int rem;
+	static struct nla_policy pmsr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
+		[NL80211_PMSR_ATTR_PEERS] = { .type = NLA_NESTED },
+	};
+	static struct nla_policy peer_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
+		[NL80211_PMSR_PEER_ATTR_ADDR] = {
+			.minlen = ETH_ALEN,
+			.maxlen = ETH_ALEN,
+		},
+		[NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_NESTED },
+	};
+	static struct nla_policy resp_policy[NL80211_PMSR_RESP_ATTR_MAX + 1] = {
+		[NL80211_PMSR_RESP_ATTR_DATA] = { .type = NLA_NESTED },
+		[NL80211_PMSR_RESP_ATTR_STATUS] = { .type = NLA_U32 },
+		[NL80211_PMSR_RESP_ATTR_HOST_TIME] = { .type = NLA_U64 },
+		[NL80211_PMSR_RESP_ATTR_AP_TSF] = { .type = NLA_U64 },
+		[NL80211_PMSR_RESP_ATTR_FINAL] = { .type = NLA_FLAG },
+	};
+
+	os_memset(&data, 0, sizeof(data));
+	if (tb[NL80211_ATTR_COOKIE]) {
+		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+		data.peer_measurement_result.cookie = cookie;
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: PR: Peer measurement cookie: %llu",
+			   (unsigned long long) cookie);
+	}
+
+	if (!tb[NL80211_ATTR_PEER_MEASUREMENTS] ||
+	    nla_parse_nested(pmsr, NL80211_PMSR_ATTR_MAX,
+			     tb[NL80211_ATTR_PEER_MEASUREMENTS], pmsr_policy))
+		return;
+
+	if (!pmsr[NL80211_PMSR_ATTR_PEERS])
+		return;
+
+	nla_for_each_nested(peer, pmsr[NL80211_PMSR_ATTR_PEERS], rem) {
+		struct nlattr *peer_tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
+		struct nlattr *resp_tb[NL80211_PMSR_RESP_ATTR_MAX + 1];
+
+		if (nla_parse_nested(peer_tb, NL80211_PMSR_PEER_ATTR_MAX,
+				     peer, peer_policy))
+			continue;
+
+		if (!peer_tb[NL80211_PMSR_PEER_ATTR_ADDR] ||
+		    !peer_tb[NL80211_PMSR_PEER_ATTR_RESP])
+			continue;
+
+		os_memcpy(data.peer_measurement_result.addr,
+			  nla_data(peer_tb[NL80211_PMSR_PEER_ATTR_ADDR]),
+			  ETH_ALEN);
+
+		if (nla_parse_nested(resp_tb, NL80211_PMSR_RESP_ATTR_MAX,
+				     peer_tb[NL80211_PMSR_PEER_ATTR_RESP],
+				     resp_policy))
+			continue;
+
+		if (resp_tb[NL80211_PMSR_RESP_ATTR_STATUS])
+			data.peer_measurement_result.status =
+				nla_get_u32(resp_tb[NL80211_PMSR_RESP_ATTR_STATUS]);
+
+		if (resp_tb[NL80211_PMSR_RESP_ATTR_HOST_TIME])
+			data.peer_measurement_result.host_time =
+				nla_get_u64(resp_tb[NL80211_PMSR_RESP_ATTR_HOST_TIME]);
+
+		if (resp_tb[NL80211_PMSR_RESP_ATTR_AP_TSF])
+			data.peer_measurement_result.ap_tsf =
+				nla_get_u64(resp_tb[NL80211_PMSR_RESP_ATTR_AP_TSF]);
+
+		if (resp_tb[NL80211_PMSR_RESP_ATTR_FINAL])
+			data.peer_measurement_result.final = 1;
+
+		if (resp_tb[NL80211_PMSR_RESP_ATTR_DATA]) {
+			struct nlattr *data_type_tb[NL80211_PMSR_TYPE_MAX + 1];
+
+			if (nla_parse_nested(data_type_tb, NL80211_PMSR_TYPE_MAX,
+					     resp_tb[NL80211_PMSR_RESP_ATTR_DATA],
+					     NULL))
+				continue;
+
+			if (data_type_tb[NL80211_PMSR_TYPE_FTM])
+				nl80211_parse_peer_ftm_result(&data.peer_measurement_result.ftm,
+							      data_type_tb[NL80211_PMSR_TYPE_FTM]);
+		}
+
+		wpa_supplicant_event(bss->ctx, EVENT_PEER_MEASUREMENT_RESULT, &data);
+		os_memset(&data.peer_measurement_result, 0,
+			  sizeof(data.peer_measurement_result));
+		if (cookie)
+			data.peer_measurement_result.cookie = cookie;
+	}
+}
+
+#endif /* CONFIG_PR */
 
 #ifdef CONFIG_IEEE80211AX
 
@@ -4562,6 +4811,11 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 	case NL80211_CMD_INCUMBENT_SIGNAL_DETECT:
 		nl80211_incumbt_sig_intf_event(bss, tb);
 		break;
+#ifdef CONFIG_PR
+	case NL80211_CMD_PEER_MEASUREMENT_RESULT:
+		nl80211_peer_measurement_result_event(bss, tb);
+		break;
+#endif /* CONFIG_PR */
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 3d05df2e3..aa2d17890 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -7610,6 +7610,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		if (data)
 			wpas_setup_link_reconfig(wpa_s, &data->reconfig_info);
 		break;
+	case EVENT_PEER_MEASUREMENT_RESULT:
+#ifdef CONFIG_PR
+		if (data)
+			wpas_pr_measurement_result(wpa_s,
+						   &data->peer_measurement_result);
+#endif /* CONFIG_PR */
+		break;
 #ifdef CONFIG_NAN
 	case EVENT_NAN_CLUSTER_JOIN:
 		wpas_nan_cluster_join(wpa_s, data->nan_cluster_join_info.bssid,
diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c
index aec7f9bab..fb844bc81 100644
--- a/wpa_supplicant/pr_supplicant.c
+++ b/wpa_supplicant/pr_supplicant.c
@@ -779,6 +779,64 @@ void wpas_pr_set_dev_ik(struct wpa_supplicant *wpa_s, const u8 *dik,
 }
 
 
+void wpas_pr_measurement_result(struct wpa_supplicant *wpa_s,
+				struct peer_measurement_result *result)
+{
+	struct pr_data *pr = wpa_s->global->pr;
+	char buf[200];
+	int len;
+
+	if (!result) {
+		wpa_printf(MSG_ERROR, "PR: Invalid measurement result");
+		return;
+	}
+
+	/* Validate cookie if we have a pending ranging request */
+	if (pr && pr->pr_pasn_params && result->cookie != 0) {
+		if (pr->pr_pasn_params->cookie != result->cookie) {
+			wpa_printf(MSG_WARNING,
+				   "PR: Cookie mismatch - expected %llu, got %llu. Ignoring result.",
+				   (unsigned long long) pr->pr_pasn_params->cookie,
+				   (unsigned long long) result->cookie);
+			return;
+		}
+	}
+
+	if (result->final) {
+		wpa_msg(wpa_s, MSG_INFO, PR_EVENT_PEER_MEASUREMENT_COMPLETE
+			"addr=" MACSTR " status=%u",
+			MAC2STR(result->addr), result->status);
+		if (pr) {
+			os_free(pr->pr_pasn_params);
+			pr->pr_pasn_params = NULL;
+		}
+		return;
+	}
+
+	/* Per-burst intermediate result */
+	len = os_snprintf(buf, sizeof(buf),
+			  PR_EVENT_PEER_MEASUREMENT "addr=" MACSTR
+			  " status=%u burst_index=%u",
+			  MAC2STR(result->addr), result->status,
+			  result->ftm.burst_index);
+
+	if (result->ftm.fail) {
+		os_snprintf(buf + len, sizeof(buf) - len, " fail=1");
+	} else {
+		if (result->ftm.rtt_avg)
+			len += os_snprintf(buf + len, sizeof(buf) - len,
+					   " rtt_avg=%lld",
+					   (long long) result->ftm.rtt_avg);
+		if (result->ftm.dist_avg)
+			os_snprintf(buf + len, sizeof(buf) - len,
+				    " dist_avg=%lld",
+				    (long long) result->ftm.dist_avg);
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+}
+
+
 #ifdef CONFIG_PASN
 
 static int wpas_pr_start_pd(struct wpa_supplicant *wpa_s, const u8 *src_addr)
diff --git a/wpa_supplicant/pr_supplicant.h b/wpa_supplicant/pr_supplicant.h
index 6972ecacb..bf8daf7a3 100644
--- a/wpa_supplicant/pr_supplicant.h
+++ b/wpa_supplicant/pr_supplicant.h
@@ -42,6 +42,8 @@ void wpas_pr_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					 unsigned int freq);
 void wpas_pr_pasn_trigger(struct wpa_supplicant *wpa_s,
 			  struct pr_pasn_ranging_params *pr_pasn_params);
+void wpas_pr_measurement_result(struct wpa_supplicant *wpa_s,
+				struct peer_measurement_result *result);
 
 #else /* CONFIG_PR */
 
@@ -115,6 +117,12 @@ static inline void wpas_pr_pasn_trigger(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline void
+wpas_pr_measurement_result(struct wpa_supplicant *wpa_s,
+			   struct peer_measurement_result *result)
+{
+}
+
 #endif /* CONFIG_PR */
 
 #endif /* PR_SUPPLICANT_H */
-- 
2.34.1




More information about the Hostap mailing list