From 8c37adf95ee0a75de582ec14c810037a0ead3415 Mon Sep 17 00:00:00 2001 From: Raj Kumar Bhagat Date: Fri, 4 Nov 2022 14:39:26 +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 RRM link measurement request to the associated station. Add support to handle the link measurement report in hostapd. Config File Change (Per BSS): rrm_link_measurement_report=1 Signed-off-by: Raj Kumar Bhagat --- hostapd/config_file.c | 4 ++ hostapd/ctrl_iface.c | 23 ++++++++ hostapd/hostapd_cli.c | 9 ++++ hostapd/main.c | 1 + src/ap/ap_drv_ops.h | 8 +++ src/ap/hostapd.h | 3 ++ src/ap/rrm.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/ap/rrm.h | 4 ++ src/common/wpa_ctrl.h | 3 ++ 9 files changed, 176 insertions(+) --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4420,6 +4420,10 @@ static int hostapd_config_fill(struct ho 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) { --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -3238,6 +3238,25 @@ static int hostapd_ctrl_iface_req_beacon } +static int hostapd_ctrl_iface_req_link_mesurement(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) { @@ -4036,6 +4055,10 @@ static int hostapd_ctrl_iface_receive_pr } 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_mesurement(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); --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1585,6 +1585,13 @@ static int hostapd_cli_cmd_req_beacon(st } +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[]) { @@ -1798,6 +1805,8 @@ static const struct hostapd_cli_cmd host "= show allowed bandwidth on each channel"}, { "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 ANDROID --- a/hostapd/main.c +++ b/hostapd/main.c @@ -301,6 +301,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 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -428,8 +428,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 */ @@ -560,6 +562,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 --- a/src/ap/rrm.c +++ b/src/ap/rrm.c @@ -677,3 +677,113 @@ void hostapd_rrm_beacon_req_tx_status(st " %u ack=%d", MAC2STR(mgmt->da), mgmt->u.action.u.rrm.dialog_token, ok); } + + +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 mesr request (token %u) timed out", + hapd->link_measurement_req_token); + hapd->link_mesr_req_active = 0; +} + + +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; + struct rrm_link_measurement_report *report; + const u8 *pos; + char report_msg[2 * 8 +1]; + + pos = mgmt->u.action.u.rrm.variable; + report = (struct rrm_link_measurement_report *) (pos - 1); + + if (!hapd->link_mesr_req_active || + (hapd->link_measurement_req_token != report->dialog_token)) { + wpa_printf(MSG_ERROR, "Unexpected Link mesr report, token %u", + report->dialog_token); + return; + } + + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); + + len = len - IEEE80211_HDRLEN - 3; + report_msg[0] = '\0'; + if (wpa_snprintf_hex(report_msg, sizeof(report_msg), pos, len) < 0) + return; + wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s", + MAC2STR(mgmt->sa), report->dialog_token, report_msg); +} + + +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 Mesr: dest addr " MACSTR, + MAC2STR(addr)); + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Request Link Mesr: dest addr is not connected"); + return -1; + } + + if (!(hapd->iface->drv_rrm_flags & + WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { + wpa_printf(MSG_INFO, + "Request Link Mesr: TX power insertion not supported"); + return -1; + } + + if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) { + wpa_printf(MSG_INFO, + "Request Link Mesr: dest sta does not support link Mesr report"); + return -1; + } + + if (hapd->link_mesr_req_active) { + wpa_printf(MSG_DEBUG, + "Request Link Mesr: 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: 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; +} --- a/src/ap/rrm.h +++ b/src/ap/rrm.h @@ -29,5 +29,9 @@ int hostapd_send_beacon_req(struct hosta 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); +void hostapd_handle_link_mesr_report(struct hostapd_data *hapd, const u8 *buf, + size_t len); #endif /* RRM_H */ --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -404,6 +404,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: */ --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -3077,6 +3077,9 @@ own_ip_addr=127.0.0.1 # Enable beacon report via radio measurements #rrm_beacon_report=1 +# Enable link measurement report via radio measurements +#rrm_link_measurement_report=1 + # Publish fine timing measurement (FTM) responder functionality # This parameter only controls publishing via Extended Capabilities element. # Actual functionality is managed outside hostapd.