[PATCH v3 13/19] wpa_supplicant: Handle LCI request
Ilan Peer
ilan.peer at intel.com
Wed Apr 6 09:42:13 PDT 2016
From: David Spinadel <david.spinadel at intel.com>
Handle radio measurement request that contains LCI request.
Send measurement report based on a configurable LCI report IE.
Signed-off-by: David Spinadel <david.spinadel at intel.com>
---
wpa_supplicant/ctrl_iface.c | 21 ++++++
wpa_supplicant/events.c | 31 ++++----
wpa_supplicant/sme.c | 3 +
wpa_supplicant/wpa_supplicant.c | 147 ++++++++++++++++++++++++++++++++++++++
wpa_supplicant/wpa_supplicant_i.h | 7 ++
5 files changed, 197 insertions(+), 12 deletions(-)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 6e91e31..78d3245 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -311,6 +311,25 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
}
+static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
+
+ if (os_strcmp(cmd, "\"\"") == 0)
+ return 0;
+
+ wpa_s->lci = wpabuf_parse_bin(cmd);
+ if (!wpa_s->lci)
+ return -1;
+
+ if (os_get_reltime(&wpa_s->lci_time))
+ return -1;
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -497,6 +516,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
} else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
wpas_mbo_update_cell_capa(wpa_s, atoi(value));
#endif /* CONFIG_MBO */
+ } else if (os_strcasecmp(cmd, "lci") == 0) {
+ ret = wpas_ctrl_iface_set_lci(wpa_s, value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index eb330dd..4f2b511 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3273,18 +3273,25 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#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;
- }
-
- 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;
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT) {
+ if (payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_radio_measurement_request(wpa_s,
+ mgmt->sa,
+ payload + 1,
+ plen - 1);
+ return;
+ } else if (payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
+ wpas_rrm_process_neighbor_rep(wpa_s, payload + 1,
+ plen - 1);
+ return;
+ } else if (payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_link_measurement_request(wpa_s,
+ mgmt->sa,
+ payload + 1,
+ plen - 1,
+ rssi);
+ return;
+ }
}
#ifdef CONFIG_FST
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index a6ace1a..d83c65d 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -186,6 +186,9 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+ if (wpa_s->lci)
+ pos[1] |= WLAN_RRM_CAPS_LCI_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 8b30c98..a27505e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -573,6 +573,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_MBO */
free_bss_tmp_disallowed(wpa_s);
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
}
@@ -6309,6 +6312,150 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
}
+static struct wpabuf *wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
+ const u8 *request, size_t len,
+ struct wpabuf *report)
+{
+ u8 token, type, subject;
+ u16 max_age = 0;
+ struct os_reltime t, diff;
+ unsigned long diff_l;
+ u8 *ptoken;
+ const u8 *subelem;
+
+ if (!wpa_s->lci)
+ return report;
+
+ if (len < 3 + 4)
+ return report;
+
+ token = *request++;
+ /* Measurement request mode isn't used */
+ request++;
+ type = *request++;
+ subject = *request++;
+
+ wpa_printf(MSG_DEBUG,
+ "Measurement request token %d type %d location subject %d",
+ token, type, subject);
+
+ if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) {
+ wpa_printf(MSG_INFO,
+ "Not building LCI report - bad type or location subject");
+ return report;
+ }
+
+ /* Subelements are formatted exactly like IEs */
+ subelem = get_ie(request, len, LCI_REQ_SUBELEMENT_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ max_age = *(u16 *)(subelem + 2);
+
+ if (os_get_reltime(&t))
+ return report;
+
+ os_reltime_sub(&t, &wpa_s->lci_time, &diff);
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ if (max_age != 0xffff && max_age < diff_l)
+ return report;
+
+ if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci)))
+ return report;
+
+ wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(report, wpabuf_len(wpa_s->lci));
+ /* We'll override user's measurement token */
+ ptoken = wpabuf_mhead_u8(report) + wpabuf_len(report);
+ wpabuf_put_buf(report, wpa_s->lci);
+ *ptoken = token;
+
+ return report;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len)
+{
+ struct wpabuf *buf, *report;
+ u8 token;
+ const u8 *ie, *end;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request. Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request. Not RRM network");
+ return;
+ }
+
+ if (len < 3) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring too short radio measurement request");
+ return;
+ }
+
+ end = frame + len;
+
+ token = *frame;
+ frame++;
+
+ /* We ignore num of repetiotions because it's not used in LCI request */
+ frame += 2;
+
+ report = NULL;
+ while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) &&
+ ie[1] >= 3) {
+ u8 msmt_type;
+
+ msmt_type = ie[4];
+ wpa_printf(MSG_INFO, "RRM request %d", msmt_type);
+
+ switch (msmt_type) {
+ case MEASURE_TYPE_LCI:
+ report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1],
+ report);
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "RRM: unsupported radio measurement request %d",
+ msmt_type);
+ }
+
+ frame = ie + ie[1] + 2;
+ }
+
+ if (!report)
+ return;
+
+ buf = wpabuf_alloc(3 + wpabuf_len(report));
+ if (!buf) {
+ wpabuf_free(report);
+ return;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+ wpabuf_put_u8(buf, token);
+
+ wpabuf_put_buf(buf, report);
+
+ 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: Radio measurement report failed. Send action failed");
+ }
+ wpabuf_free(buf);
+ wpabuf_free(report);
+}
+
+
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *frame, size_t len,
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 211f4d1..3b23af0 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1058,6 +1058,10 @@ struct wpa_supplicant {
* the bss_temp_disallowed list for other purposes as well.
*/
struct dl_list bss_tmp_disallowed;
+
+ /* Content of a measure report IE with type 8 (LCI), own location. */
+ struct wpabuf *lci;
+ struct os_reltime lci_time;
};
@@ -1168,6 +1172,9 @@ 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_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len);
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *frame, size_t len,
--
1.9.1
More information about the Hostap
mailing list