From 1be706e8620a8201e32e2627a752936e39d7ec1e Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Thu, 4 Apr 2024 11:58:09 +0530 Subject: [PATCH] hostapd: Add RRM link measurement request support RRM link measurement request/report management frames are used to get the radio link information between the connected stations. Add new hostapd_cli command req_link_measurement to send an RRM link measurement request to an associated station. Add support to handle the link measurement report in hostapd. RRM link measurement support can be enabled with the following new configuration parameter: rrm_link_measurement_report=1 Signed-off-by: Raj Kumar Bhagat Signed-off-by: Yuvarani V --- hostapd/config_file.c | 4 ++ hostapd/ctrl_iface.c | 23 ++++++++ hostapd/hostapd.conf | 3 ++ hostapd/hostapd_cli.c | 9 ++++ hostapd/main.c | 1 + src/ap/hostapd.h | 3 ++ src/ap/rrm.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/ap/rrm.h | 2 + src/common/wpa_ctrl.h | 3 ++ 9 files changed, 169 insertions(+) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 56b2df3ae..7a32c22f3 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4662,6 +4662,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE | WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE | WLAN_RRM_CAPS_BEACON_REPORT_TABLE; + } else if (os_strcmp(buf, "rrm_link_measurement_report") == 0) { + if (atoi(pos)) + bss->radio_measurements[0] |= + WLAN_RRM_CAPS_LINK_MEASUREMENT; } else if (os_strcmp(buf, "gas_address3") == 0) { bss->gas_address3 = atoi(pos); } else if (os_strcmp(buf, "stationary_ap") == 0) { diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 23cc52a28..9fb6010c7 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -3207,6 +3207,26 @@ static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd, } +static int hostapd_ctrl_iface_req_link_measurement(struct hostapd_data *hapd, + const char *cmd, char *reply, + size_t reply_size) +{ + u8 addr[ETH_ALEN]; + int ret; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_ERROR, + "CTRL: REQ_LINK_MEASUREMENT: Invalid MAC address"); + return -1; + } + + ret = hostapd_send_link_measurement_req(hapd, addr); + if (ret >= 0) + ret = os_snprintf(reply, reply_size, "%d", ret); + return ret; +} + + static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd, char *buf, size_t buflen) { @@ -4185,6 +4205,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) { reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11, reply, reply_size); + } else if (os_strncmp(buf, "REQ_LINK_MEASUREMENT ", 21) == 0) { + reply_len = hostapd_ctrl_iface_req_link_measurement( + hapd, buf + 21, reply, reply_size); } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply, reply_size); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index d80abcac0..e34d75c86 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -3112,6 +3112,9 @@ own_ip_addr=127.0.0.1 # Enable neighbor report via radio measurements #rrm_neighbor_report=1 +# Enable link measurement report via radio measurements +#rrm_link_measurement_report=1 + # Enable beacon report via radio measurements #rrm_beacon_report=1 diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index a9d326de8..e1fe2860b 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1605,6 +1605,13 @@ static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_req_link_measurement(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "REQ_LINK_MEASUREMENT", 1, argc, argv); +} + + static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1847,6 +1854,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { " = poll a STA to check connectivity with a QoS null frame" }, { "req_beacon", hostapd_cli_cmd_req_beacon, NULL, " [req_mode=] = send a Beacon report request to a station" }, + { "req_link_measurement", hostapd_cli_cmd_req_link_measurement, NULL, + " = send a link measurement report request to a station"}, { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, "= reload wpa_psk_file only" }, #ifdef CONFIG_IEEE80211R_AP diff --git a/hostapd/main.c b/hostapd/main.c index a43d3a5be..8b9b96a69 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -309,6 +309,7 @@ setup_mld: iface->drv_flags = capa.flags; iface->drv_flags2 = capa.flags2; + iface->drv_rrm_flags = capa.rrm_flags; iface->probe_resp_offloads = capa.probe_resp_offloads; /* * Use default extended capa values from per-radio information diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 85f8975fa..4797d7d93 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -405,8 +405,10 @@ struct hostapd_data { u8 beacon_req_token; u8 lci_req_token; u8 range_req_token; + u8 link_measurement_req_token; unsigned int lci_req_active:1; unsigned int range_req_active:1; + unsigned int link_mesr_req_active:1; int dhcp_sock; /* UDP socket used with the DHCP server */ @@ -577,6 +579,7 @@ struct hostapd_iface { u64 drv_flags; u64 drv_flags2; + unsigned int drv_rrm_flags; /* * A bitmap of supported protocols for probe response offload. See diff --git a/src/ap/rrm.c b/src/ap/rrm.c index f2d5cd16e..fbcddf3f9 100644 --- a/src/ap/rrm.c +++ b/src/ap/rrm.c @@ -334,6 +334,53 @@ static void hostapd_handle_nei_report_req(struct hostapd_data *hapd, } +static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + wpa_printf(MSG_DEBUG, + "RRM: Link measurement request (token %u) timed out", + hapd->link_measurement_req_token); + hapd->link_mesr_req_active = 0; +} + + +static void hostapd_handle_link_mesr_report(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_report *report; + const u8 *pos, *end; + char report_msg[2 * 8 + 1]; + + end = buf + len; + pos = mgmt->u.action.u.rrm.variable; + report = (const struct rrm_link_measurement_report *) (pos - 1); + if (end - (const u8 *) report < (int) sizeof(*report)) + return; + + if (!hapd->link_mesr_req_active || + (hapd->link_measurement_req_token != report->dialog_token)) { + wpa_printf(MSG_INFO, + "Unexpected Link measurement report, token %u", + report->dialog_token); + return; + } + + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); + + report_msg[0] = '\0'; + if (wpa_snprintf_hex(report_msg, sizeof(report_msg), + pos, end - pos) < 0) + return; + + wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s", + MAC2STR(mgmt->sa), report->dialog_token, report_msg); +} + + void hostapd_handle_radio_measurement(struct hostapd_data *hapd, const u8 *buf, size_t len) { @@ -356,6 +403,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_REPORT: + hostapd_handle_link_mesr_report(hapd, buf, len); + break; default: wpa_printf(MSG_DEBUG, "RRM action %u is not supported", mgmt->u.action.u.rrm.action); @@ -563,6 +613,7 @@ void hostapd_clean_rrm(struct hostapd_data *hapd) hapd->lci_req_active = 0; eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); hapd->range_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); } @@ -672,3 +723,73 @@ void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, " %u ack=%d", MAC2STR(mgmt->da), mgmt->u.action.u.rrm.dialog_token, ok); } + + +int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr) +{ + struct wpabuf *buf; + struct sta_info *sta; + int ret; + + wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR, + MAC2STR(addr)); + + if (!(hapd->iface->drv_rrm_flags & + WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: the driver does not support TX power insertion"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: specied STA is not connected"); + return -1; + } + + if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: destination STA does not support link measurement"); + return -1; + } + + if (hapd->link_mesr_req_active) { + wpa_printf(MSG_DEBUG, + "Request Link Measurement: request already in process - overriding"); + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, + hapd, NULL); + } + + /* Action + Action type + token + Tx Power used + Max Tx Power = 5 */ + buf = wpabuf_alloc(5); + if (!buf) + return -1; + + hapd->link_measurement_req_token++; + if (!hapd->link_measurement_req_token) + hapd->link_measurement_req_token++; + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST); + wpabuf_put_u8(buf, hapd->link_measurement_req_token); + /* NOTE: The driver is expected to fill the Tx Power Used and Max Tx + * Power */ + wpabuf_put_u8(buf, 0); + wpabuf_put_u8(buf, 0); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + if (ret < 0) + return ret; + + hapd->link_mesr_req_active = 1; + + eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, + hostapd_link_mesr_rep_timeout_handler, hapd, + NULL); + + return hapd->link_measurement_req_token; +} diff --git a/src/ap/rrm.h b/src/ap/rrm.h index 02cd522ee..17751e02c 100644 --- a/src/ap/rrm.h +++ b/src/ap/rrm.h @@ -29,5 +29,7 @@ int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr, void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ok); +int hostapd_send_link_measurement_req(struct hostapd_data *hapd, + const u8 *addr); #endif /* RRM_H */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index c5bb9abd7..f6142501e 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -413,6 +413,9 @@ extern "C" { /* parameters: */ #define BEACON_RESP_RX "BEACON-RESP-RX " +/* parameters: */ +#define LINK_MSR_RESP_RX "LINK-MSR-RESP-RX " + /* PMKSA cache entry added; parameters: */ #define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED " /* PMKSA cache entry removed; parameters: */