wpa_supplicant: Add support for Neighbor Report
Add the ability to send a Neighbor Report Request (part of RRM). Requester is then notified once the report arrives. Signed-off-by: Assaf Krauss <assaf.krauss@intel.com>
This commit is contained in:
parent
2526ccd95a
commit
d89c0701db
4 changed files with 208 additions and 0 deletions
|
@ -340,6 +340,18 @@
|
||||||
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
|
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
|
||||||
#define WLAN_TDLS_DISCOVERY_REQUEST 10
|
#define WLAN_TDLS_DISCOVERY_REQUEST 10
|
||||||
|
|
||||||
|
/* Radio Measurement Action codes */
|
||||||
|
#define WLAN_RRM_RADIO_MEASUREMENT_REQUEST 0
|
||||||
|
#define WLAN_RRM_RADIO_MEASUREMENT_REPORT 1
|
||||||
|
#define WLAN_RRM_LINK_MEASUREMENT_REQUEST 2
|
||||||
|
#define WLAN_RRM_LINK_MEASUREMENT_REPORT 3
|
||||||
|
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
|
||||||
|
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
|
||||||
|
|
||||||
|
/* Radio Measurement capabilities (from RRM Capabilities IE) */
|
||||||
|
/* byte 1 (out of 5) */
|
||||||
|
#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
|
||||||
|
|
||||||
/* Timeout Interval Type */
|
/* Timeout Interval Type */
|
||||||
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
|
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
|
||||||
#define WLAN_TIMEOUT_KEY_LIFETIME 2
|
#define WLAN_TIMEOUT_KEY_LIFETIME 2
|
||||||
|
|
|
@ -2866,6 +2866,12 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_INTERWORKING */
|
#endif /* CONFIG_INTERWORKING */
|
||||||
|
|
||||||
|
if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
|
||||||
|
payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
|
||||||
|
wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
|
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
|
||||||
category, payload, plen, freq);
|
category, payload, plen, freq);
|
||||||
if (wpa_s->ifmsh)
|
if (wpa_s->ifmsh)
|
||||||
|
|
|
@ -4913,6 +4913,24 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
|
||||||
|
{
|
||||||
|
struct rrm_data *rrm = data;
|
||||||
|
|
||||||
|
if (!rrm->notify_neighbor_rep) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"RRM: Unexpected neighbor report timeout");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
|
||||||
|
rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
|
||||||
|
|
||||||
|
rrm->notify_neighbor_rep = NULL;
|
||||||
|
rrm->neighbor_rep_cb_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
|
* wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
|
||||||
* @wpa_s: Pointer to wpa_supplicant
|
* @wpa_s: Pointer to wpa_supplicant
|
||||||
|
@ -4920,4 +4938,153 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
|
||||||
void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
|
void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
wpa_s->rrm.rrm_used = 0;
|
wpa_s->rrm.rrm_used = 0;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
|
||||||
|
NULL);
|
||||||
|
if (wpa_s->rrm.notify_neighbor_rep)
|
||||||
|
wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
|
||||||
|
wpa_s->rrm.next_neighbor_rep_token = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
|
||||||
|
* @wpa_s: Pointer to wpa_supplicant
|
||||||
|
* @report: Neighbor report buffer, prefixed by a 1-byte dialog token
|
||||||
|
* @report_len: Length of neighbor report buffer
|
||||||
|
*/
|
||||||
|
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *report, size_t report_len)
|
||||||
|
{
|
||||||
|
struct wpabuf *neighbor_rep;
|
||||||
|
|
||||||
|
wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
|
||||||
|
if (report_len < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RRM: Discarding neighbor report with token %d (expected %d)",
|
||||||
|
report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!wpa_s->rrm.notify_neighbor_rep) {
|
||||||
|
wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skipping the first byte, which is only an id (dialog token) */
|
||||||
|
neighbor_rep = wpabuf_alloc(report_len - 1);
|
||||||
|
if (neighbor_rep == NULL)
|
||||||
|
return;
|
||||||
|
wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
|
||||||
|
wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
|
||||||
|
report[0]);
|
||||||
|
wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
|
||||||
|
neighbor_rep);
|
||||||
|
wpa_s->rrm.notify_neighbor_rep = NULL;
|
||||||
|
wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
|
||||||
|
* @wpa_s: Pointer to wpa_supplicant
|
||||||
|
* @cb: Callback function to be called once the requested report arrives, or
|
||||||
|
* timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
|
||||||
|
* In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
|
||||||
|
* the requester's responsibility to free it.
|
||||||
|
* In the latter case NULL will be sent in 'neighbor_rep'.
|
||||||
|
* @cb_ctx: Context value to send the callback function
|
||||||
|
* Returns: 0 in case of success, negative error code otherwise
|
||||||
|
*
|
||||||
|
* In case there is a previous request which has not been answered yet, the
|
||||||
|
* new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
|
||||||
|
* Request must contain a callback function.
|
||||||
|
* The Neighbor Report Request sent to the AP will specify the current SSID.
|
||||||
|
*/
|
||||||
|
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
|
||||||
|
void (*cb)(void *ctx,
|
||||||
|
struct wpabuf *neighbor_rep),
|
||||||
|
void *cb_ctx)
|
||||||
|
{
|
||||||
|
struct wpabuf *buf;
|
||||||
|
const u8 *rrm_ie;
|
||||||
|
|
||||||
|
if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
|
||||||
|
return -ENOTCONN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wpa_s->rrm.rrm_used) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
|
||||||
|
WLAN_EID_RRM_ENABLED_CAPABILITIES);
|
||||||
|
if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
|
||||||
|
!(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RRM: No network support for Neighbor Report.");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cb) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RRM: Neighbor Report request must provide a callback.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Refuse if there's a live request */
|
||||||
|
if (wpa_s->rrm.notify_neighbor_rep) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RRM: Currently handling previous Neighbor Report.");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5 = action category + action code + dialog token + IE hdr */
|
||||||
|
buf = wpabuf_alloc(5 + wpa_s->current_ssid->ssid_len);
|
||||||
|
if (buf == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RRM: Failed to allocate Neighbor Report Request");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
|
||||||
|
wpa_ssid_txt(wpa_s->current_ssid->ssid,
|
||||||
|
wpa_s->current_ssid->ssid_len),
|
||||||
|
wpa_s->rrm.next_neighbor_rep_token);
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
|
||||||
|
wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
|
||||||
|
wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_SSID);
|
||||||
|
wpabuf_put_u8(buf, wpa_s->current_ssid->ssid_len);
|
||||||
|
wpabuf_put_data(buf, wpa_s->current_ssid->ssid,
|
||||||
|
wpa_s->current_ssid->ssid_len);
|
||||||
|
|
||||||
|
wpa_s->rrm.next_neighbor_rep_token++;
|
||||||
|
|
||||||
|
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
|
||||||
|
wpa_s->own_addr, wpa_s->bssid,
|
||||||
|
wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RRM: Failed to send Neighbor Report Request");
|
||||||
|
wpabuf_free(buf);
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
|
||||||
|
wpa_s->rrm.notify_neighbor_rep = cb;
|
||||||
|
eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
|
||||||
|
wpas_rrm_neighbor_rep_timeout_handler,
|
||||||
|
&wpa_s->rrm, NULL);
|
||||||
|
|
||||||
|
wpabuf_free(buf);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,12 +378,29 @@ struct wpa_used_freq_data {
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define RRM_NEIGHBOR_REPORT_TIMEOUT 1 /* 1 second for AP to send a report */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct rrm_data - Data used for managing RRM features
|
* struct rrm_data - Data used for managing RRM features
|
||||||
*/
|
*/
|
||||||
struct rrm_data {
|
struct rrm_data {
|
||||||
/* rrm_used - indication regarding the current connection */
|
/* rrm_used - indication regarding the current connection */
|
||||||
unsigned int rrm_used:1;
|
unsigned int rrm_used:1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* notify_neighbor_rep - Callback for notifying report requester
|
||||||
|
*/
|
||||||
|
void (*notify_neighbor_rep)(void *ctx, struct wpabuf *neighbor_rep);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* neighbor_rep_cb_ctx - Callback context
|
||||||
|
* Received in the callback registration, and sent to the callback
|
||||||
|
* function as a parameter.
|
||||||
|
*/
|
||||||
|
void *neighbor_rep_cb_ctx;
|
||||||
|
|
||||||
|
/* next_neighbor_rep_token - Next request's dialog token */
|
||||||
|
u8 next_neighbor_rep_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1006,6 +1023,12 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
|
||||||
void add_freq(int *freqs, int *num_freqs, int freq);
|
void add_freq(int *freqs, int *num_freqs, int freq);
|
||||||
|
|
||||||
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
|
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
|
||||||
|
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
|
||||||
|
const u8 *report, size_t report_len);
|
||||||
|
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
|
||||||
|
void (*cb)(void *ctx,
|
||||||
|
struct wpabuf *neighbor_rep),
|
||||||
|
void *cb_ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
|
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
|
||||||
|
|
Loading…
Reference in a new issue