wpa_supplicant: Handle LCI request
Handle radio measurement request that contains LCI request. Send measurement report based on a configurable LCI report element. The LCI report element is configured over the control interface with SET lci <hexdump of the element> and cleared with SET lci "" Signed-off-by: David Spinadel <david.spinadel@intel.com>
This commit is contained in:
parent
220754c553
commit
4a742011ab
5 changed files with 194 additions and 0 deletions
|
@ -311,6 +311,33 @@ 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,
|
||||
const char *cmd)
|
||||
{
|
||||
struct wpabuf *lci;
|
||||
|
||||
if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
|
||||
wpabuf_free(wpa_s->lci);
|
||||
wpa_s->lci = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lci = wpabuf_parse_bin(cmd);
|
||||
if (!lci)
|
||||
return -1;
|
||||
|
||||
if (os_get_reltime(&wpa_s->lci_time)) {
|
||||
wpabuf_free(lci);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpabuf_free(wpa_s->lci);
|
||||
wpa_s->lci = lci;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
|
||||
char *cmd)
|
||||
{
|
||||
|
@ -497,6 +524,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);
|
||||
|
|
|
@ -3278,6 +3278,14 @@ 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_RADIO_MEASUREMENT_REQUEST) {
|
||||
wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa,
|
||||
payload + 1,
|
||||
plen - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
|
||||
payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
|
||||
wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -575,6 +575,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6340,6 +6343,147 @@ 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 || 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 %u type %u location subject %u",
|
||||
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 elements */
|
||||
subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
|
||||
if (subelem && subelem[1] == 2)
|
||||
max_age = WPA_GET_LE16(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_put(report, 0);
|
||||
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++;
|
||||
|
||||
/* Ignore number of repetitions 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_DEBUG, "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);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
wpabuf_free(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: Sending Action frame failed");
|
||||
}
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
|
||||
const u8 *src,
|
||||
const u8 *frame, size_t len,
|
||||
|
|
|
@ -1058,6 +1058,13 @@ struct wpa_supplicant {
|
|||
* the bss_temp_disallowed list for other purposes as well.
|
||||
*/
|
||||
struct dl_list bss_tmp_disallowed;
|
||||
|
||||
/*
|
||||
* Content of a measurement report element with type 8 (LCI),
|
||||
* own location.
|
||||
*/
|
||||
struct wpabuf *lci;
|
||||
struct os_reltime lci_time;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1168,6 +1175,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,
|
||||
|
|
Loading…
Reference in a new issue