diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 85744379b..25260f3d2 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -8222,19 +8222,37 @@ static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep) static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s, char *cmd) { - struct wpa_ssid ssid; - struct wpa_ssid *ssid_p = NULL; - int ret = 0; + struct wpa_ssid_value ssid, *ssid_p = NULL; + int ret, lci = 0, civic = 0; + char *ssid_s; - if (os_strncmp(cmd, " ssid=", 6) == 0) { - ssid.ssid_len = os_strlen(cmd + 6); - if (ssid.ssid_len > SSID_MAX_LEN) + ssid_s = os_strstr(cmd, "ssid="); + if (ssid_s) { + if (ssid_parse(ssid_s + 5, &ssid)) { + wpa_printf(MSG_ERROR, + "CTRL: Send Neighbor Report: bad SSID"); return -1; - ssid.ssid = (u8 *) (cmd + 6); + } + ssid_p = &ssid; + + /* + * Move cmd after the SSID text that may include "lci" or + * "civic". + */ + cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' '); + if (cmd) + cmd++; + } - ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, + if (cmd && os_strstr(cmd, "lci")) + lci = 1; + + if (cmd && os_strstr(cmd, "civic")) + civic = 1; + + ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic, wpas_ctrl_neighbor_rep_cb, wpa_s); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 36a7a4ebd..7099fb31b 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -3455,8 +3455,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { }, { "neighbor_rep_request", wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none, - "[ssid=] = Trigger request to AP for neighboring AP report " - "(with optional given SSID, default: current SSID)" + "[ssid=] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)" }, { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none, "= flush ERP keys" }, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 45930f9cd..1f0fcd0ac 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -6162,11 +6162,19 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, #define ECANCELED -1 #endif +/* Measurement Request element + Location Subject + Maximum Age subelement */ +#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4) +/* Measurement Request element + Location Civic Request */ +#define MEASURE_REQUEST_CIVIC_LEN (3 + 5) + + /** * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP * @wpa_s: Pointer to wpa_supplicant * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE * is sent in the request. + * @lci: if set, neighbor request will include LCI request + * @civic: if set, neighbor request will include civic location request * @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 @@ -6180,7 +6188,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, * Request must contain a callback function. */ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, + const struct wpa_ssid_value *ssid, + int lci, int civic, void (*cb)(void *ctx, struct wpabuf *neighbor_rep), void *cb_ctx) @@ -6221,7 +6230,9 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, } /* 3 = action category + action code + dialog token */ - buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0)); + buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) + + (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) + + (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0)); if (buf == NULL) { wpa_printf(MSG_DEBUG, "RRM: Failed to allocate Neighbor Report Request"); @@ -6241,6 +6252,72 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len); } + if (lci) { + /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN); + + /* + * Measurement token; nonzero number that is unique among the + * Measurement Request elements in a particular frame. + */ + wpabuf_put_u8(buf, 1); /* Measurement Token */ + + /* + * Parallel, Enable, Request, and Report bits are 0, Duration is + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */ + + /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */ + /* Location Subject */ + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + + /* Optional Subelements */ + /* + * IEEE P802.11-REVmc/D5.0 Figure 9-170 + * The Maximum Age subelement is required, otherwise the AP can + * send only data that was determined after receiving the + * request. Setting it here to unlimited age. + */ + wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); + wpabuf_put_u8(buf, 2); + wpabuf_put_le16(buf, 0xffff); + } + + if (civic) { + /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN); + + /* + * Measurement token; nonzero number that is unique among the + * Measurement Request elements in a particular frame. + */ + wpabuf_put_u8(buf, 2); /* Measurement Token */ + + /* + * Parallel, Enable, Request, and Report bits are 0, Duration is + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + /* Measurement Type */ + wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC); + + /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14: + * Location Civic request */ + /* Location Subject */ + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */ + /* Location Service Interval Units: Seconds */ + wpabuf_put_u8(buf, 0); + /* Location Service Interval: 0 - Only one report is requested + */ + wpabuf_put_le16(buf, 0); + /* No optional subelements */ + } + wpa_s->rrm.next_neighbor_rep_token++; if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index e6fc45787..211f4d11a 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1163,7 +1163,8 @@ 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, - const struct wpa_ssid *ssid, + const struct wpa_ssid_value *ssid, + int lci, int civic, void (*cb)(void *ctx, struct wpabuf *neighbor_rep), void *cb_ctx);