wpa_supplicant: Handle link measurement requests
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Wed, 5 Nov 2014 08:42:56 +0000 (03:42 -0500)
committerJouni Malinen <j@w1.fi>
Sat, 22 Nov 2014 19:45:07 +0000 (21:45 +0200)
Send link measurement response when a request is received. Advertise
only RCPI, computing it from the RSSI of the request. The TX power field
is left to be filled by the driver. All other fields are not published.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
src/common/ieee802_11_defs.h
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 0566e93..26b1493 100644 (file)
 
 /* Radio Measurement capabilities (from RRM Capabilities IE) */
 /* byte 1 (out of 5) */
+#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
 #define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
 
 /* Timeout Interval Type */
@@ -1308,4 +1309,30 @@ enum wnm_sleep_mode_subelement_id {
 #define CHAN_SWITCH_MODE_ALLOW_TX      0
 #define CHAN_SWITCH_MODE_BLOCK_TX      1
 
+struct tpc_report {
+       u8 eid;
+       u8 len;
+       u8 tx_power;
+       u8 link_margin;
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
+struct rrm_link_measurement_request {
+       u8 dialog_token;
+       s8 tx_power;
+       s8 max_tp;
+       u8 variable[0];
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */
+struct rrm_link_measurement_report {
+       u8 dialog_token;
+       struct tpc_report tpc;
+       u8 rx_ant_id;
+       u8 tx_ant_id;
+       u8 rcpi;
+       u8 rsni;
+       u8 variable[0];
+} STRUCT_PACKED;
+
 #endif /* IEEE802_11_DEFS_H */
index 6609816..06b09ef 100644 (file)
@@ -2785,7 +2785,8 @@ static void wpa_supplicant_update_channel_list(
 
 
 static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
-                                     const u8 *frame, size_t len, int freq)
+                                     const u8 *frame, size_t len, int freq,
+                                     int rssi)
 {
        const struct ieee80211_mgmt *mgmt;
        const u8 *payload;
@@ -2872,6 +2873,14 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+           payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
+               wpas_rrm_handle_link_measurement_request(wpa_s, mgmt->sa,
+                                                        payload + 1, plen - 1,
+                                                        rssi);
+               return;
+       }
+
        wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
                           category, payload, plen, freq);
        if (wpa_s->ifmsh)
@@ -3258,7 +3267,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                wpas_event_rx_mgmt_action(
                                        wpa_s, data->rx_mgmt.frame,
                                        data->rx_mgmt.frame_len,
-                                       data->rx_mgmt.freq);
+                                       data->rx_mgmt.freq,
+                                       data->rx_mgmt.ssi_signal);
                                break;
                        }
 
index f1c4957..8c88a23 100644 (file)
@@ -178,10 +178,14 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
 
        wpa_printf(MSG_DEBUG, "RRM: Adding RRM IE to Association Request");
        pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
-        /* IE body is made of bit flags, all initialized to 0 */
        os_memset(pos, 0, 2 + rrm_ie_len);
        *pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
        *pos++ = rrm_ie_len;
+
+       /* Set supported capabilites flags */
+       if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
+               *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
        wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
        wpa_s->rrm.rrm_used = 1;
 }
index 196c6ff..96125a1 100644 (file)
@@ -5090,3 +5090,82 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
        wpabuf_free(buf);
        return 0;
 }
+
+
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+                                             const u8 *src,
+                                             const u8 *frame, size_t len,
+                                             int rssi)
+{
+       struct wpabuf *buf;
+       const struct rrm_link_measurement_request *req;
+       struct rrm_link_measurement_report report;
+
+       if (wpa_s->wpa_state != WPA_COMPLETED) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Ignoring link measurement request. Not associated");
+               return;
+       }
+
+       if (!wpa_s->rrm.rrm_used) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Ignoring link measurement request. Not RRM network");
+               return;
+       }
+
+       if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Measurement report failed. TX power insertion not supported");
+               return;
+       }
+
+       req = (const struct rrm_link_measurement_request *) frame;
+       if (len < sizeof(*req)) {
+               wpa_printf(MSG_INFO,
+                          "RRM: Link measurement report failed. Request too short");
+               return;
+       }
+
+       os_memset(&report, 0, sizeof(report));
+       report.tpc.eid = WLAN_EID_TPC_REPORT;
+       report.tpc.len = 2;
+       report.rsni = 255; /* 255 indicates that RSNI is not available */
+       report.dialog_token = req->dialog_token;
+
+       /*
+        * It's possible to estimate RCPI based on RSSI in dBm. This
+        * calculation will not reflect the correct value for high rates,
+        * but it's good enough for Action frames which are transmitted
+        * with up to 24 Mbps rates.
+        */
+       if (!rssi)
+               report.rcpi = 255; /* not available */
+       else if (rssi < -110)
+               report.rcpi = 0;
+       else if (rssi > 0)
+               report.rcpi = 220;
+       else
+               report.rcpi = (rssi + 110) * 2;
+
+       /* action_category + action_code */
+       buf = wpabuf_alloc(2 + sizeof(report));
+       if (buf == NULL) {
+               wpa_printf(MSG_ERROR,
+                          "RRM: Link measurement report failed. Buffer allocation failed");
+               return;
+       }
+
+       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+       wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+       wpabuf_put_data(buf, &report, sizeof(report));
+       wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
+                   wpabuf_head(buf), wpabuf_len(buf));
+
+       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+                               wpa_s->own_addr, wpa_s->bssid,
+                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
+               wpa_printf(MSG_ERROR,
+                          "RRM: Link measurement report failed. Send action failed");
+       }
+       wpabuf_free(buf);
+}
index 9979972..a5227dd 100644 (file)
@@ -1030,6 +1030,10 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
                                       void (*cb)(void *ctx,
                                                  struct wpabuf *neighbor_rep),
                                       void *cb_ctx);
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+                                             const u8 *src,
+                                             const u8 *frame, size_t len,
+                                             int rssi);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response