]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Add RRM link measurement request support
authorRaj Kumar Bhagat <quic_rajkbhag@quicinc.com>
Thu, 4 Apr 2024 06:28:09 +0000 (11:58 +0530)
committerJouni Malinen <j@w1.fi>
Mon, 15 Apr 2024 19:28:55 +0000 (22:28 +0300)
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 <quic_rajkbhag@quicinc.com>
Signed-off-by: Yuvarani V <quic_yuvarani@quicinc.com>
hostapd/config_file.c
hostapd/ctrl_iface.c
hostapd/hostapd.conf
hostapd/hostapd_cli.c
hostapd/main.c
src/ap/hostapd.h
src/ap/rrm.c
src/ap/rrm.h
src/common/wpa_ctrl.h

index 56b2df3ae09c4f1d67d60da5288e74cbe7533f57..7a32c22f32d9f9091112b99e77e262ee3e8becba 100644 (file)
@@ -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) {
index 23cc52a2878215c260951ed9f74bc2f4cdf81eef..9fb6010c73628584a6e738668df032d75b6982e0 100644 (file)
@@ -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);
index d80abcac0e0e0031b88ae139b105ac66e1738b53..e34d75c8692a5da79c427cfb4d0221a68827a878 100644 (file)
@@ -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
 
index a9d326de8b3275d06da926e521ca81a6234f1c15..e1fe2860b3de14654e416ae6c7dd97b8e3721a77 100644 (file)
@@ -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[] = {
          "<addr> = poll a STA to check connectivity with a QoS null frame" },
        { "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
          "<addr> [req_mode=] <measurement request hexdump>  = send a Beacon report request to a station" },
+       { "req_link_measurement", hostapd_cli_cmd_req_link_measurement, NULL,
+         "<addr> = 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
index a43d3a5be1d5a539a0276472ea1b9c6ec3b63284..8b9b96a690798445aca497448bbc268d46301107 100644 (file)
@@ -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
index 85f8975fa9590d3f5c6c677647e8072999f00106..4797d7d93ad7c8c2f11681582383866d96ffadc9 100644 (file)
@@ -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
index f2d5cd16e885853c445d19c3ed4afbd5a94d6f50..fbcddf3f98c918b39cfabb6a4aabde4e98c75463 100644 (file)
@@ -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;
+}
index 02cd522ee9d633c493db700e13baed180bcae022..17751e02c958995caf56c7ca75e6cf4d5dee0148 100644 (file)
@@ -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 */
index c5bb9abd7b641653fcc51037a90433a5abf4d9a6..f6142501e440db58488ada915e0324735cbc5aed 100644 (file)
@@ -413,6 +413,9 @@ extern "C" {
 /* parameters: <STA address> <dialog token> <report mode> <beacon report> */
 #define BEACON_RESP_RX "BEACON-RESP-RX "
 
+/* parameters: <STA address> <dialog token> <link measurement report> */
+#define LINK_MSR_RESP_RX "LINK-MSR-RESP-RX "
+
 /* PMKSA cache entry added; parameters: <BSSID> <network_id> */
 #define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED "
 /* PMKSA cache entry removed; parameters: <BSSID> <network_id> */