From 70d1e72849c3ff0e762f6f4cdb6173ef74a9a4aa Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Wed, 5 Nov 2014 03:42:56 -0500 Subject: [PATCH] wpa_supplicant: Handle link measurement requests 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 --- src/common/ieee802_11_defs.h | 27 +++++++++++ wpa_supplicant/events.c | 14 +++++- wpa_supplicant/sme.c | 6 ++- wpa_supplicant/wpa_supplicant.c | 79 +++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 4 ++ 5 files changed, 127 insertions(+), 3 deletions(-) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 0566e9378..26b1493f5 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -350,6 +350,7 @@ /* 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 */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 660981621..06b09ef3f 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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; } diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index f1c49572e..8c88a2393 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -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; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 196c6ff4c..96125a110 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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); +} diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 99799725f..a5227ddfa 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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