From: David Spinadel <david.spinadel@xxxxxxxxx> 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@xxxxxxxxx> --- wpa_supplicant/ctrl_iface.c | 21 ++++++ wpa_supplicant/events.c | 31 ++++---- wpa_supplicant/sme.c | 3 + wpa_supplicant/wpa_supplicant.c | 148 ++++++++++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 7 ++ 5 files changed, 198 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 e7ff150..65d95d9 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..18ba0d6 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,151 @@ 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; + + 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; + } + + token = *frame; + frame++; + len--; + + /* We ignore num of repetiotions because it's not used in LCI request */ + frame += 2; + len -= 2; + + report = NULL; + while ((ie = get_ie(frame, len, 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; + len -= ie - frame + 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap