[PATCH 04/15] RRM: Respond to Link Measurement Request frames in AP mode

Andrei-Alexandru Bleortu me at andrei-z.com
Sun Oct 4 03:41:57 PDT 2026


hostapd advertises Link Measurement in the RM Enabled Capabilities
element when rrm_link_measurement_report=1 and sends Link Measurement
Requests to STAs, but a Link Measurement Request from a STA was not even
delivered from the driver, so the advertised capability had no
responder (IEEE Std 802.11-2024, 11.10.11).

With drivers that insert the transmit power into the TPC Report element
(the same condition under which wpa_supplicant answers these requests),
subscribe to Link Measurement Request frames and answer them with a Link
Measurement Report: the RCPI of the last frame received from the STA,
which 9.6.6.5 allows, or 255 when the driver does not report a signal,
and RSNI not available.

Assisted-by: LLM
Signed-off-by: Andrei-Alexandru Bleortu <me at andrei-z.com>
---
 src/ap/rrm.c                 | 65 ++++++++++++++++++++++++++++++++++++
 src/drivers/driver_nl80211.c |  5 +++
 2 files changed, 70 insertions(+)

diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index 73771e4c5..2dc95d00a 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -346,6 +346,68 @@ static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data,
 }
 
 
+/* IEEE Std 802.11-2024, 11.10.11: answer a STA's Link Measurement Request */
+static void hostapd_handle_link_mesr_req(struct hostapd_data *hapd,
+					 const u8 *buf, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+	const struct rrm_link_measurement_request *req;
+	struct rrm_link_measurement_report report;
+	struct hostap_sta_driver_data data;
+	struct sta_info *sta;
+	struct wpabuf *msg;
+
+	req = (const struct rrm_link_measurement_request *)
+		(mgmt->u.action.u.rrm.variable - 1);
+	if (buf + len - (const u8 *) req < (int) sizeof(*req))
+		return;
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (!sta || !(sta->flags & WLAN_STA_ASSOC) ||
+	    !(hapd->conf->radio_measurements[0] &
+	      WLAN_RRM_CAPS_LINK_MEASUREMENT))
+		return;
+
+	/* The driver fills in the transmit power of the report frame */
+	if (!(hapd->iface->drv_rrm_flags &
+	      WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Link Measurement Request from " MACSTR
+			   " ignored - no TX power insertion",
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+
+	os_memset(&report, 0, sizeof(report));
+	report.dialog_token = req->dialog_token;
+	report.tpc.eid = WLAN_EID_TPC_REPORT;
+	report.tpc.len = 2;
+	/* RCPI of the last frame received from the STA (9.6.6.5); a driver
+	 * need not report the signal */
+	os_memset(&data, 0, sizeof(data));
+	if (hostapd_drv_read_sta_data(hapd, &data, mgmt->sa) == 0 &&
+	    data.signal != 0 && data.signal != -WPA_INVALID_NOISE)
+		report.rcpi = rssi_to_rcpi(data.signal);
+	else
+		report.rcpi = 255; /* not available */
+	report.rsni = 255; /* not available */
+
+	msg = wpabuf_alloc(2 + sizeof(report));
+	if (!msg)
+		return;
+	wpabuf_put_u8(msg, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(msg, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+	wpabuf_put_data(msg, &report, sizeof(report));
+
+	if (hostapd_drv_send_action(hapd, hapd->iface->freq, 0, mgmt->sa,
+				    wpabuf_head(msg), wpabuf_len(msg)) < 0)
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Failed to send Link Measurement Report to "
+			   MACSTR, MAC2STR(mgmt->sa));
+	wpabuf_free(msg);
+}
+
+
 static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd,
 					    const u8 *buf, size_t len)
 {
@@ -403,6 +465,9 @@ void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
 	case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
 		hostapd_handle_nei_report_req(hapd, buf, len);
 		break;
+	case WLAN_RRM_LINK_MEASUREMENT_REQUEST:
+		hostapd_handle_link_mesr_req(hapd, buf, len);
+		break;
 	case WLAN_RRM_LINK_MEASUREMENT_REPORT:
 		hostapd_handle_link_mesr_report(hapd, buf, len);
 		break;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c6578cb86..e3d731f3d 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3117,6 +3117,11 @@ static int nl80211_action_subscribe_ap(struct i802_bss *bss)
 	/* RRM Measurement Report */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
 		ret = -1;
+	/* RRM Link Measurement Request, answered with the TX power the driver
+	 * inserts */
+	if ((bss->drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
+	    nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0)
+		ret = -1;
 	/* RRM Link Measurement Report */
 	if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
 		ret = -1;
-- 
2.47.3





More information about the Hostap mailing list