1 1.1 christos /* 2 1.1 christos * wpa_supplicant - Radio Measurements 3 1.1 christos * Copyright (c) 2003-2016, Jouni Malinen <j (at) w1.fi> 4 1.1 christos * 5 1.1 christos * This software may be distributed under the terms of the BSD license. 6 1.1 christos * See README for more details. 7 1.1 christos */ 8 1.1 christos 9 1.1 christos #include "includes.h" 10 1.1 christos 11 1.1 christos #include "utils/common.h" 12 1.1 christos #include "utils/eloop.h" 13 1.1 christos #include "common/ieee802_11_common.h" 14 1.1 christos #include "wpa_supplicant_i.h" 15 1.1 christos #include "driver_i.h" 16 1.1 christos #include "bss.h" 17 1.1 christos #include "scan.h" 18 1.1 christos #include "p2p_supplicant.h" 19 1.1 christos 20 1.1 christos 21 1.1 christos static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx) 22 1.1 christos { 23 1.1 christos struct rrm_data *rrm = data; 24 1.1 christos 25 1.1 christos if (!rrm->notify_neighbor_rep) { 26 1.1 christos wpa_printf(MSG_ERROR, 27 1.1 christos "RRM: Unexpected neighbor report timeout"); 28 1.1 christos return; 29 1.1 christos } 30 1.1 christos 31 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE"); 32 1.1 christos rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL); 33 1.1 christos 34 1.1 christos rrm->notify_neighbor_rep = NULL; 35 1.1 christos rrm->neighbor_rep_cb_ctx = NULL; 36 1.1 christos } 37 1.1 christos 38 1.1 christos 39 1.1 christos /* 40 1.1 christos * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant 41 1.1 christos * @wpa_s: Pointer to wpa_supplicant 42 1.1 christos */ 43 1.1 christos void wpas_rrm_reset(struct wpa_supplicant *wpa_s) 44 1.1 christos { 45 1.1 christos wpa_s->rrm.rrm_used = 0; 46 1.1 christos 47 1.1 christos eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, 48 1.1 christos NULL); 49 1.1 christos if (wpa_s->rrm.notify_neighbor_rep) 50 1.1 christos wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); 51 1.1 christos wpa_s->rrm.next_neighbor_rep_token = 1; 52 1.1 christos wpas_clear_beacon_rep_data(wpa_s); 53 1.1 christos } 54 1.1 christos 55 1.1 christos 56 1.1 christos /* 57 1.1 christos * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report 58 1.1 christos * @wpa_s: Pointer to wpa_supplicant 59 1.1 christos * @report: Neighbor report buffer, prefixed by a 1-byte dialog token 60 1.1 christos * @report_len: Length of neighbor report buffer 61 1.1 christos */ 62 1.1 christos void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, 63 1.1 christos const u8 *report, size_t report_len) 64 1.1 christos { 65 1.1 christos struct wpabuf *neighbor_rep; 66 1.1 christos 67 1.1 christos wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len); 68 1.1 christos if (report_len < 1) 69 1.1 christos return; 70 1.1 christos 71 1.1 christos if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) { 72 1.1 christos wpa_printf(MSG_DEBUG, 73 1.1 christos "RRM: Discarding neighbor report with token %d (expected %d)", 74 1.1 christos report[0], wpa_s->rrm.next_neighbor_rep_token - 1); 75 1.1 christos return; 76 1.1 christos } 77 1.1 christos 78 1.1 christos eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, 79 1.1 christos NULL); 80 1.1 christos 81 1.1 christos if (!wpa_s->rrm.notify_neighbor_rep) { 82 1.1.1.3 christos wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report"); 83 1.1 christos return; 84 1.1 christos } 85 1.1 christos 86 1.1 christos /* skipping the first byte, which is only an id (dialog token) */ 87 1.1 christos neighbor_rep = wpabuf_alloc(report_len - 1); 88 1.1 christos if (!neighbor_rep) { 89 1.1 christos wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); 90 1.1 christos return; 91 1.1 christos } 92 1.1 christos wpabuf_put_data(neighbor_rep, report + 1, report_len - 1); 93 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)", 94 1.1.1.3 christos report[0]); 95 1.1 christos wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx, 96 1.1 christos neighbor_rep); 97 1.1 christos wpa_s->rrm.notify_neighbor_rep = NULL; 98 1.1 christos wpa_s->rrm.neighbor_rep_cb_ctx = NULL; 99 1.1 christos } 100 1.1 christos 101 1.1 christos 102 1.1 christos #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) 103 1.1 christos /* Workaround different, undefined for Windows, error codes used here */ 104 1.1.1.3 christos #ifndef ENOTCONN 105 1.1 christos #define ENOTCONN -1 106 1.1.1.3 christos #endif 107 1.1.1.3 christos #ifndef EOPNOTSUPP 108 1.1 christos #define EOPNOTSUPP -1 109 1.1.1.3 christos #endif 110 1.1.1.3 christos #ifndef ECANCELED 111 1.1 christos #define ECANCELED -1 112 1.1 christos #endif 113 1.1.1.3 christos #endif 114 1.1 christos 115 1.1 christos /* Measurement Request element + Location Subject + Maximum Age subelement */ 116 1.1 christos #define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4) 117 1.1 christos /* Measurement Request element + Location Civic Request */ 118 1.1 christos #define MEASURE_REQUEST_CIVIC_LEN (3 + 5) 119 1.1 christos 120 1.1 christos 121 1.1 christos /** 122 1.1 christos * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP 123 1.1 christos * @wpa_s: Pointer to wpa_supplicant 124 1.1 christos * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE 125 1.1 christos * is sent in the request. 126 1.1 christos * @lci: if set, neighbor request will include LCI request 127 1.1 christos * @civic: if set, neighbor request will include civic location request 128 1.1 christos * @cb: Callback function to be called once the requested report arrives, or 129 1.1 christos * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds. 130 1.1 christos * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's 131 1.1 christos * the requester's responsibility to free it. 132 1.1 christos * In the latter case NULL will be sent in 'neighbor_rep'. 133 1.1 christos * @cb_ctx: Context value to send the callback function 134 1.1 christos * Returns: 0 in case of success, negative error code otherwise 135 1.1 christos * 136 1.1 christos * In case there is a previous request which has not been answered yet, the 137 1.1 christos * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT. 138 1.1 christos * Request must contain a callback function. 139 1.1 christos */ 140 1.1 christos int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, 141 1.1 christos const struct wpa_ssid_value *ssid, 142 1.1 christos int lci, int civic, 143 1.1 christos void (*cb)(void *ctx, 144 1.1 christos struct wpabuf *neighbor_rep), 145 1.1 christos void *cb_ctx) 146 1.1 christos { 147 1.1 christos struct wpabuf *buf; 148 1.1 christos const u8 *rrm_ie; 149 1.1 christos 150 1.1 christos if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) { 151 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No connection, no RRM."); 152 1.1 christos return -ENOTCONN; 153 1.1 christos } 154 1.1 christos 155 1.1 christos if (!wpa_s->rrm.rrm_used) { 156 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No RRM in current connection."); 157 1.1 christos return -EOPNOTSUPP; 158 1.1 christos } 159 1.1 christos 160 1.1 christos rrm_ie = wpa_bss_get_ie(wpa_s->current_bss, 161 1.1 christos WLAN_EID_RRM_ENABLED_CAPABILITIES); 162 1.1 christos if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) || 163 1.1 christos !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) { 164 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, 165 1.1.1.3 christos "RRM: No network support for Neighbor Report."); 166 1.1 christos return -EOPNOTSUPP; 167 1.1 christos } 168 1.1 christos 169 1.1 christos /* Refuse if there's a live request */ 170 1.1 christos if (wpa_s->rrm.notify_neighbor_rep) { 171 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, 172 1.1.1.3 christos "RRM: Currently handling previous Neighbor Report."); 173 1.1 christos return -EBUSY; 174 1.1 christos } 175 1.1 christos 176 1.1 christos /* 3 = action category + action code + dialog token */ 177 1.1 christos buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) + 178 1.1 christos (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) + 179 1.1 christos (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0)); 180 1.1 christos if (buf == NULL) { 181 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, 182 1.1.1.3 christos "RRM: Failed to allocate Neighbor Report Request"); 183 1.1 christos return -ENOMEM; 184 1.1 christos } 185 1.1 christos 186 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, 187 1.1.1.3 christos "RRM: Neighbor report request (for %s), token=%d", 188 1.1.1.3 christos (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""), 189 1.1.1.3 christos wpa_s->rrm.next_neighbor_rep_token); 190 1.1 christos 191 1.1 christos wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 192 1.1 christos wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST); 193 1.1 christos wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token); 194 1.1 christos if (ssid) { 195 1.1 christos wpabuf_put_u8(buf, WLAN_EID_SSID); 196 1.1 christos wpabuf_put_u8(buf, ssid->ssid_len); 197 1.1 christos wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len); 198 1.1 christos } 199 1.1 christos 200 1.1 christos if (lci) { 201 1.1 christos /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ 202 1.1 christos wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 203 1.1 christos wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN); 204 1.1 christos 205 1.1 christos /* 206 1.1 christos * Measurement token; nonzero number that is unique among the 207 1.1 christos * Measurement Request elements in a particular frame. 208 1.1 christos */ 209 1.1 christos wpabuf_put_u8(buf, 1); /* Measurement Token */ 210 1.1 christos 211 1.1 christos /* 212 1.1 christos * Parallel, Enable, Request, and Report bits are 0, Duration is 213 1.1 christos * reserved. 214 1.1 christos */ 215 1.1 christos wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ 216 1.1 christos wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */ 217 1.1 christos 218 1.1 christos /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */ 219 1.1 christos /* Location Subject */ 220 1.1 christos wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); 221 1.1 christos 222 1.1 christos /* Optional Subelements */ 223 1.1 christos /* 224 1.1 christos * IEEE P802.11-REVmc/D5.0 Figure 9-170 225 1.1 christos * The Maximum Age subelement is required, otherwise the AP can 226 1.1 christos * send only data that was determined after receiving the 227 1.1 christos * request. Setting it here to unlimited age. 228 1.1 christos */ 229 1.1 christos wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); 230 1.1 christos wpabuf_put_u8(buf, 2); 231 1.1 christos wpabuf_put_le16(buf, 0xffff); 232 1.1 christos } 233 1.1 christos 234 1.1 christos if (civic) { 235 1.1 christos /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ 236 1.1 christos wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 237 1.1 christos wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN); 238 1.1 christos 239 1.1 christos /* 240 1.1 christos * Measurement token; nonzero number that is unique among the 241 1.1 christos * Measurement Request elements in a particular frame. 242 1.1 christos */ 243 1.1 christos wpabuf_put_u8(buf, 2); /* Measurement Token */ 244 1.1 christos 245 1.1 christos /* 246 1.1 christos * Parallel, Enable, Request, and Report bits are 0, Duration is 247 1.1 christos * reserved. 248 1.1 christos */ 249 1.1 christos wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ 250 1.1 christos /* Measurement Type */ 251 1.1 christos wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC); 252 1.1 christos 253 1.1 christos /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14: 254 1.1 christos * Location Civic request */ 255 1.1 christos /* Location Subject */ 256 1.1 christos wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); 257 1.1 christos wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */ 258 1.1 christos /* Location Service Interval Units: Seconds */ 259 1.1 christos wpabuf_put_u8(buf, 0); 260 1.1 christos /* Location Service Interval: 0 - Only one report is requested 261 1.1 christos */ 262 1.1 christos wpabuf_put_le16(buf, 0); 263 1.1 christos /* No optional subelements */ 264 1.1 christos } 265 1.1 christos 266 1.1 christos wpa_s->rrm.next_neighbor_rep_token++; 267 1.1 christos 268 1.1 christos if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 269 1.1 christos wpa_s->own_addr, wpa_s->bssid, 270 1.1 christos wpabuf_head(buf), wpabuf_len(buf), 0) < 0) { 271 1.1.1.3 christos wpa_dbg(wpa_s, MSG_DEBUG, 272 1.1.1.3 christos "RRM: Failed to send Neighbor Report Request"); 273 1.1 christos wpabuf_free(buf); 274 1.1 christos return -ECANCELED; 275 1.1 christos } 276 1.1 christos 277 1.1 christos wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx; 278 1.1 christos wpa_s->rrm.notify_neighbor_rep = cb; 279 1.1 christos eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0, 280 1.1 christos wpas_rrm_neighbor_rep_timeout_handler, 281 1.1 christos &wpa_s->rrm, NULL); 282 1.1 christos 283 1.1 christos wpabuf_free(buf); 284 1.1 christos return 0; 285 1.1 christos } 286 1.1 christos 287 1.1 christos 288 1.1 christos static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type, 289 1.1 christos const u8 *data, size_t data_len) 290 1.1 christos { 291 1.1 christos if (wpabuf_resize(buf, 5 + data_len)) 292 1.1 christos return -1; 293 1.1 christos 294 1.1 christos wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT); 295 1.1 christos wpabuf_put_u8(*buf, 3 + data_len); 296 1.1 christos wpabuf_put_u8(*buf, token); 297 1.1 christos wpabuf_put_u8(*buf, mode); 298 1.1 christos wpabuf_put_u8(*buf, type); 299 1.1 christos 300 1.1 christos if (data_len) 301 1.1 christos wpabuf_put_data(*buf, data, data_len); 302 1.1 christos 303 1.1 christos return 0; 304 1.1 christos } 305 1.1 christos 306 1.1 christos 307 1.1 christos static int 308 1.1 christos wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s, 309 1.1 christos const struct rrm_measurement_request_element *req, 310 1.1 christos struct wpabuf **buf) 311 1.1 christos { 312 1.1 christos u8 subject; 313 1.1 christos u16 max_age = 0; 314 1.1 christos struct os_reltime t, diff; 315 1.1 christos unsigned long diff_l; 316 1.1 christos const u8 *subelem; 317 1.1 christos const u8 *request = req->variable; 318 1.1 christos size_t len = req->len - 3; 319 1.1 christos 320 1.1 christos if (len < 1) 321 1.1 christos return -1; 322 1.1 christos 323 1.1 christos if (!wpa_s->lci) 324 1.1 christos goto reject; 325 1.1 christos 326 1.1 christos subject = *request++; 327 1.1 christos len--; 328 1.1 christos 329 1.1 christos wpa_printf(MSG_DEBUG, "Measurement request location subject=%u", 330 1.1 christos subject); 331 1.1 christos 332 1.1 christos if (subject != LOCATION_SUBJECT_REMOTE) { 333 1.1 christos wpa_printf(MSG_INFO, 334 1.1 christos "Not building LCI report - bad location subject"); 335 1.1 christos return 0; 336 1.1 christos } 337 1.1 christos 338 1.1 christos /* Subelements are formatted exactly like elements */ 339 1.1 christos wpa_hexdump(MSG_DEBUG, "LCI request subelements", request, len); 340 1.1 christos subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE); 341 1.1 christos if (subelem && subelem[1] == 2) 342 1.1 christos max_age = WPA_GET_LE16(subelem + 2); 343 1.1 christos 344 1.1 christos if (os_get_reltime(&t)) 345 1.1 christos goto reject; 346 1.1 christos 347 1.1 christos os_reltime_sub(&t, &wpa_s->lci_time, &diff); 348 1.1 christos /* LCI age is calculated in 10th of a second units. */ 349 1.1 christos diff_l = diff.sec * 10 + diff.usec / 100000; 350 1.1 christos 351 1.1 christos if (max_age != 0xffff && max_age < diff_l) 352 1.1 christos goto reject; 353 1.1 christos 354 1.1 christos if (wpas_rrm_report_elem(buf, req->token, 355 1.1 christos MEASUREMENT_REPORT_MODE_ACCEPT, req->type, 356 1.1 christos wpabuf_head_u8(wpa_s->lci), 357 1.1 christos wpabuf_len(wpa_s->lci)) < 0) { 358 1.1 christos wpa_printf(MSG_DEBUG, "Failed to add LCI report element"); 359 1.1 christos return -1; 360 1.1 christos } 361 1.1 christos 362 1.1 christos return 0; 363 1.1 christos 364 1.1 christos reject: 365 1.1 christos if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && 366 1.1 christos wpas_rrm_report_elem(buf, req->token, 367 1.1 christos MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE, 368 1.1 christos req->type, NULL, 0) < 0) { 369 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); 370 1.1 christos return -1; 371 1.1 christos } 372 1.1 christos 373 1.1 christos return 0; 374 1.1 christos } 375 1.1 christos 376 1.1 christos 377 1.1 christos static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s, 378 1.1 christos const u8 *data, size_t len) 379 1.1 christos { 380 1.1 christos struct wpabuf *report = wpabuf_alloc(len + 3); 381 1.1 christos 382 1.1 christos if (!report) 383 1.1 christos return; 384 1.1 christos 385 1.1 christos wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT); 386 1.1 christos wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT); 387 1.1 christos wpabuf_put_u8(report, wpa_s->rrm.token); 388 1.1 christos 389 1.1 christos wpabuf_put_data(report, data, len); 390 1.1 christos 391 1.1 christos if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 392 1.1 christos wpa_s->own_addr, wpa_s->bssid, 393 1.1 christos wpabuf_head(report), wpabuf_len(report), 0)) { 394 1.1 christos wpa_printf(MSG_ERROR, 395 1.1 christos "RRM: Radio measurement report failed: Sending Action frame failed"); 396 1.1 christos } 397 1.1 christos 398 1.1 christos wpabuf_free(report); 399 1.1 christos } 400 1.1 christos 401 1.1 christos 402 1.1.1.2 christos static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len) 403 1.1.1.2 christos { 404 1.1.1.2 christos struct rrm_measurement_report_element *msr_rep; 405 1.1.1.2 christos u8 *end = pos + len; 406 1.1.1.2 christos u8 *msr_rep_end; 407 1.1.1.2 christos struct rrm_measurement_beacon_report *rep = NULL; 408 1.1.1.2 christos u8 *subelem; 409 1.1.1.2 christos 410 1.1.1.2 christos /* Find the last beacon report element */ 411 1.1.1.2 christos while (end - pos >= (int) sizeof(*msr_rep)) { 412 1.1.1.2 christos msr_rep = (struct rrm_measurement_report_element *) pos; 413 1.1.1.2 christos msr_rep_end = pos + msr_rep->len + 2; 414 1.1.1.2 christos 415 1.1.1.2 christos if (msr_rep->eid != WLAN_EID_MEASURE_REPORT || 416 1.1.1.2 christos msr_rep_end > end) { 417 1.1.1.2 christos /* Should not happen. This indicates a bug. */ 418 1.1.1.2 christos wpa_printf(MSG_ERROR, 419 1.1.1.2 christos "RRM: non-measurement report element in measurement report frame"); 420 1.1.1.2 christos return -1; 421 1.1.1.2 christos } 422 1.1.1.2 christos 423 1.1.1.2 christos if (msr_rep->type == MEASURE_TYPE_BEACON) 424 1.1.1.2 christos rep = (struct rrm_measurement_beacon_report *) 425 1.1.1.2 christos msr_rep->variable; 426 1.1.1.2 christos 427 1.1.1.2 christos pos += pos[1] + 2; 428 1.1.1.2 christos } 429 1.1.1.2 christos 430 1.1.1.2 christos if (!rep) 431 1.1.1.2 christos return 0; 432 1.1.1.2 christos 433 1.1.1.2 christos subelem = rep->variable; 434 1.1.1.2 christos while (subelem + 2 < msr_rep_end && 435 1.1.1.2 christos subelem[0] != WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION) 436 1.1.1.2 christos subelem += 2 + subelem[1]; 437 1.1.1.2 christos 438 1.1.1.2 christos if (subelem + 2 < msr_rep_end && 439 1.1.1.2 christos subelem[0] == WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION && 440 1.1.1.2 christos subelem[1] == 1 && 441 1.1.1.2 christos subelem + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end) 442 1.1.1.2 christos subelem[2] = 1; 443 1.1.1.2 christos 444 1.1.1.2 christos return 0; 445 1.1.1.2 christos } 446 1.1.1.2 christos 447 1.1.1.2 christos 448 1.1 christos static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s, 449 1.1 christos struct wpabuf *buf) 450 1.1 christos { 451 1.1 christos int len = wpabuf_len(buf); 452 1.1.1.2 christos u8 *pos = wpabuf_mhead_u8(buf), *next = pos; 453 1.1 christos 454 1.1 christos #define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3) 455 1.1 christos 456 1.1 christos while (len) { 457 1.1 christos int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len; 458 1.1 christos 459 1.1.1.2 christos if (send_len == len) 460 1.1.1.2 christos wpas_rrm_beacon_rep_update_last_frame(pos, len); 461 1.1.1.2 christos 462 1.1 christos if (send_len == len || 463 1.1 christos (send_len + next[1] + 2) > MPDU_REPORT_LEN) { 464 1.1 christos wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len); 465 1.1 christos len -= send_len; 466 1.1 christos pos = next; 467 1.1 christos } 468 1.1 christos 469 1.1 christos if (len) 470 1.1 christos next += next[1] + 2; 471 1.1 christos } 472 1.1 christos #undef MPDU_REPORT_LEN 473 1.1 christos } 474 1.1 christos 475 1.1 christos 476 1.1 christos static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels, 477 1.1 christos int *freqs) 478 1.1 christos { 479 1.1 christos size_t i; 480 1.1 christos 481 1.1 christos for (i = 0; i < num_primary_channels; i++) { 482 1.1 christos u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4; 483 1.1 christos 484 1.1 christos freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan); 485 1.1 christos /* ieee80211_chan_to_freq() is not really meant for this 486 1.1 christos * conversion of 20 MHz primary channel numbers for wider VHT 487 1.1 christos * channels, so handle those as special cases here for now. */ 488 1.1 christos if (freqs[i] < 0 && 489 1.1 christos (op_class == 128 || op_class == 129 || op_class == 130)) 490 1.1 christos freqs[i] = 5000 + 5 * primary_chan; 491 1.1 christos if (freqs[i] < 0) { 492 1.1 christos wpa_printf(MSG_DEBUG, 493 1.1 christos "Beacon Report: Invalid channel %u", 494 1.1 christos chan); 495 1.1 christos return -1; 496 1.1 christos } 497 1.1 christos } 498 1.1 christos 499 1.1 christos return 0; 500 1.1 christos } 501 1.1 christos 502 1.1 christos 503 1.1 christos static int * wpas_add_channels(const struct oper_class_map *op, 504 1.1.1.3 christos struct hostapd_hw_modes *mode, 505 1.1 christos const u8 *channels, const u8 size) 506 1.1 christos { 507 1.1 christos int *freqs, *next_freq; 508 1.1 christos u8 num_primary_channels, i; 509 1.1 christos u8 num_chans; 510 1.1 christos 511 1.1 christos num_chans = channels ? size : 512 1.1 christos (op->max_chan - op->min_chan) / op->inc + 1; 513 1.1 christos 514 1.1 christos if (op->bw == BW80 || op->bw == BW80P80) 515 1.1 christos num_primary_channels = 4; 516 1.1 christos else if (op->bw == BW160) 517 1.1 christos num_primary_channels = 8; 518 1.1.1.3 christos else if (op->bw == BW320) 519 1.1.1.3 christos num_primary_channels = 16; 520 1.1 christos else 521 1.1 christos num_primary_channels = 1; 522 1.1 christos 523 1.1 christos /* one extra place for the zero-terminator */ 524 1.1 christos freqs = os_calloc(num_chans * num_primary_channels + 1, sizeof(*freqs)); 525 1.1 christos if (!freqs) { 526 1.1 christos wpa_printf(MSG_ERROR, 527 1.1 christos "Beacon Report: Failed to allocate freqs array"); 528 1.1 christos return NULL; 529 1.1 christos } 530 1.1 christos 531 1.1 christos next_freq = freqs; 532 1.1 christos for (i = 0; i < num_chans; i++) { 533 1.1 christos u8 chan = channels ? channels[i] : op->min_chan + i * op->inc; 534 1.1.1.3 christos enum chan_allowed res = verify_channel(mode, op->op_class, chan, 535 1.1.1.3 christos op->bw); 536 1.1 christos 537 1.1.1.3 christos if (res == NOT_ALLOWED) 538 1.1 christos continue; 539 1.1 christos 540 1.1 christos if (wpas_add_channel(op->op_class, chan, num_primary_channels, 541 1.1 christos next_freq) < 0) { 542 1.1 christos os_free(freqs); 543 1.1 christos return NULL; 544 1.1 christos } 545 1.1 christos 546 1.1 christos next_freq += num_primary_channels; 547 1.1 christos } 548 1.1 christos 549 1.1 christos if (!freqs[0]) { 550 1.1 christos os_free(freqs); 551 1.1 christos return NULL; 552 1.1 christos } 553 1.1 christos 554 1.1 christos return freqs; 555 1.1 christos } 556 1.1 christos 557 1.1 christos 558 1.1 christos static int * wpas_op_class_freqs(const struct oper_class_map *op, 559 1.1.1.3 christos struct hostapd_hw_modes *mode) 560 1.1 christos { 561 1.1.1.3 christos u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 }; 562 1.1.1.3 christos u8 channels_160mhz_5ghz[] = { 50, 114, 163 }; 563 1.1.1.3 christos u8 channels_80mhz_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 564 1.1.1.3 christos 167, 183, 199, 215 }; 565 1.1.1.3 christos u8 channels_160mhz_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 }; 566 1.1.1.3 christos u8 channels_320mhz_6ghz[] = { 31, 63, 95, 127, 159, 191 }; 567 1.1.1.3 christos const u8 *channels = NULL; 568 1.1.1.3 christos size_t num_chan = 0; 569 1.1.1.3 christos bool is_6ghz = is_6ghz_op_class(op->op_class); 570 1.1 christos 571 1.1 christos /* 572 1.1 christos * When adding all channels in the operating class, 80 + 80 MHz 573 1.1 christos * operating classes are like 80 MHz channels because we add all valid 574 1.1 christos * channels anyway. 575 1.1 christos */ 576 1.1.1.3 christos if (op->bw == BW80 || op->bw == BW80P80) { 577 1.1.1.3 christos channels = is_6ghz ? channels_80mhz_6ghz : channels_80mhz_5ghz; 578 1.1.1.3 christos num_chan = is_6ghz ? ARRAY_SIZE(channels_80mhz_6ghz) : 579 1.1.1.3 christos ARRAY_SIZE(channels_80mhz_5ghz); 580 1.1.1.3 christos } else if (op->bw == BW160) { 581 1.1.1.3 christos channels = is_6ghz ? channels_160mhz_6ghz : 582 1.1.1.3 christos channels_160mhz_5ghz; 583 1.1.1.3 christos num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) : 584 1.1.1.3 christos ARRAY_SIZE(channels_160mhz_5ghz); 585 1.1.1.3 christos } else if (op->bw == BW320) { 586 1.1.1.3 christos channels = channels_320mhz_6ghz; 587 1.1.1.3 christos num_chan = ARRAY_SIZE(channels_320mhz_6ghz); 588 1.1.1.3 christos } 589 1.1 christos 590 1.1.1.3 christos return wpas_add_channels(op, mode, channels, num_chan); 591 1.1 christos } 592 1.1 christos 593 1.1 christos 594 1.1.1.3 christos static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, 595 1.1 christos const char *country, const u8 *subelems, 596 1.1 christos size_t len) 597 1.1 christos { 598 1.1 christos int *freqs = NULL, *new_freqs; 599 1.1 christos const u8 *end = subelems + len; 600 1.1 christos 601 1.1 christos while (end - subelems > 2) { 602 1.1 christos const struct oper_class_map *op; 603 1.1 christos const u8 *ap_chan_elem, *pos; 604 1.1 christos u8 left; 605 1.1 christos struct hostapd_hw_modes *mode; 606 1.1 christos 607 1.1 christos ap_chan_elem = get_ie(subelems, end - subelems, 608 1.1 christos WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL); 609 1.1 christos if (!ap_chan_elem) 610 1.1 christos break; 611 1.1 christos pos = ap_chan_elem + 2; 612 1.1 christos left = ap_chan_elem[1]; 613 1.1 christos if (left < 1) 614 1.1 christos break; 615 1.1 christos subelems = ap_chan_elem + 2 + left; 616 1.1 christos 617 1.1 christos op = get_oper_class(country, *pos); 618 1.1 christos if (!op) { 619 1.1 christos wpa_printf(MSG_DEBUG, 620 1.1 christos "Beacon request: unknown operating class in AP Channel Report subelement %u", 621 1.1 christos *pos); 622 1.1 christos goto out; 623 1.1 christos } 624 1.1 christos pos++; 625 1.1 christos left--; 626 1.1 christos 627 1.1.1.3 christos mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode, 628 1.1.1.3 christos is_6ghz_op_class(op->op_class)); 629 1.1 christos if (!mode) 630 1.1 christos continue; 631 1.1 christos 632 1.1 christos /* 633 1.1 christos * For 80 + 80 MHz operating classes, this AP Channel Report 634 1.1 christos * element should be followed by another element specifying 635 1.1 christos * the second 80 MHz channel. For now just add this 80 MHz 636 1.1 christos * channel, the second 80 MHz channel will be added when the 637 1.1 christos * next element is parsed. 638 1.1 christos * TODO: Verify that this AP Channel Report element is followed 639 1.1 christos * by a corresponding AP Channel Report element as specified in 640 1.1 christos * IEEE Std 802.11-2016, 11.11.9.1. 641 1.1 christos */ 642 1.1.1.3 christos new_freqs = wpas_add_channels(op, mode, pos, left); 643 1.1 christos if (new_freqs) 644 1.1 christos int_array_concat(&freqs, new_freqs); 645 1.1 christos 646 1.1 christos os_free(new_freqs); 647 1.1 christos } 648 1.1 christos 649 1.1 christos return freqs; 650 1.1 christos out: 651 1.1 christos os_free(freqs); 652 1.1 christos return NULL; 653 1.1 christos } 654 1.1 christos 655 1.1 christos 656 1.1 christos static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, 657 1.1.1.3 christos u8 op_class, u8 chan, 658 1.1 christos const u8 *subelems, size_t len) 659 1.1 christos { 660 1.1 christos int *freqs = NULL, *ext_freqs = NULL; 661 1.1 christos struct hostapd_hw_modes *mode; 662 1.1 christos const char *country = NULL; 663 1.1 christos const struct oper_class_map *op; 664 1.1 christos const u8 *elem; 665 1.1 christos 666 1.1 christos if (!wpa_s->current_bss) 667 1.1 christos return NULL; 668 1.1 christos elem = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY); 669 1.1 christos if (elem && elem[1] >= 2) 670 1.1 christos country = (const char *) (elem + 2); 671 1.1 christos 672 1.1 christos op = get_oper_class(country, op_class); 673 1.1 christos if (!op) { 674 1.1 christos wpa_printf(MSG_DEBUG, 675 1.1 christos "Beacon request: invalid operating class %d", 676 1.1 christos op_class); 677 1.1 christos return NULL; 678 1.1 christos } 679 1.1 christos 680 1.1.1.3 christos mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode, 681 1.1.1.3 christos is_6ghz_op_class(op->op_class)); 682 1.1 christos if (!mode) 683 1.1 christos return NULL; 684 1.1 christos 685 1.1 christos switch (chan) { 686 1.1 christos case 0: 687 1.1.1.3 christos freqs = wpas_op_class_freqs(op, mode); 688 1.1 christos if (!freqs) 689 1.1 christos return NULL; 690 1.1 christos break; 691 1.1 christos case 255: 692 1.1 christos /* freqs will be added from AP channel subelements */ 693 1.1 christos break; 694 1.1 christos default: 695 1.1.1.3 christos freqs = wpas_add_channels(op, mode, &chan, 1); 696 1.1 christos if (!freqs) 697 1.1 christos return NULL; 698 1.1 christos break; 699 1.1 christos } 700 1.1 christos 701 1.1.1.3 christos ext_freqs = wpas_channel_report_freqs(wpa_s, country, subelems, len); 702 1.1 christos if (ext_freqs) { 703 1.1 christos int_array_concat(&freqs, ext_freqs); 704 1.1 christos os_free(ext_freqs); 705 1.1 christos int_array_sort_unique(freqs); 706 1.1 christos } 707 1.1 christos 708 1.1 christos return freqs; 709 1.1 christos } 710 1.1 christos 711 1.1 christos 712 1.1.1.3 christos int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len, 713 1.1.1.3 christos u8 *op_class, u8 *chan, u8 *phy_type) 714 1.1 christos { 715 1.1 christos const u8 *ie; 716 1.1 christos int sec_chan = 0, vht = 0; 717 1.1 christos struct ieee80211_ht_operation *ht_oper = NULL; 718 1.1 christos struct ieee80211_vht_operation *vht_oper = NULL; 719 1.1 christos u8 seg0, seg1; 720 1.1 christos 721 1.1 christos ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); 722 1.1 christos if (ie && ie[1] >= sizeof(struct ieee80211_ht_operation)) { 723 1.1 christos u8 sec_chan_offset; 724 1.1 christos 725 1.1 christos ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 726 1.1 christos sec_chan_offset = ht_oper->ht_param & 727 1.1 christos HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 728 1.1 christos if (sec_chan_offset == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 729 1.1 christos sec_chan = 1; 730 1.1 christos else if (sec_chan_offset == 731 1.1 christos HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 732 1.1 christos sec_chan = -1; 733 1.1 christos } 734 1.1 christos 735 1.1 christos ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); 736 1.1 christos if (ie && ie[1] >= sizeof(struct ieee80211_vht_operation)) { 737 1.1 christos vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 738 1.1 christos 739 1.1 christos switch (vht_oper->vht_op_info_chwidth) { 740 1.1.1.3 christos case CHANWIDTH_80MHZ: 741 1.1 christos seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx; 742 1.1 christos seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx; 743 1.1 christos if (seg1 && abs(seg1 - seg0) == 8) 744 1.1.1.3 christos vht = CONF_OPER_CHWIDTH_160MHZ; 745 1.1 christos else if (seg1) 746 1.1.1.3 christos vht = CONF_OPER_CHWIDTH_80P80MHZ; 747 1.1 christos else 748 1.1.1.3 christos vht = CONF_OPER_CHWIDTH_80MHZ; 749 1.1 christos break; 750 1.1.1.3 christos case CHANWIDTH_160MHZ: 751 1.1.1.3 christos vht = CONF_OPER_CHWIDTH_160MHZ; 752 1.1 christos break; 753 1.1.1.3 christos case CHANWIDTH_80P80MHZ: 754 1.1.1.3 christos vht = CONF_OPER_CHWIDTH_80P80MHZ; 755 1.1 christos break; 756 1.1 christos default: 757 1.1.1.3 christos vht = CONF_OPER_CHWIDTH_USE_HT; 758 1.1 christos break; 759 1.1 christos } 760 1.1 christos } 761 1.1 christos 762 1.1 christos if (ieee80211_freq_to_channel_ext(freq, sec_chan, vht, op_class, 763 1.1 christos chan) == NUM_HOSTAPD_MODES) { 764 1.1 christos wpa_printf(MSG_DEBUG, 765 1.1 christos "Cannot determine operating class and channel"); 766 1.1 christos return -1; 767 1.1 christos } 768 1.1 christos 769 1.1 christos *phy_type = ieee80211_get_phy_type(freq, ht_oper != NULL, 770 1.1 christos vht_oper != NULL); 771 1.1 christos if (*phy_type == PHY_TYPE_UNSPECIFIED) { 772 1.1 christos wpa_printf(MSG_DEBUG, "Cannot determine phy type"); 773 1.1 christos return -1; 774 1.1 christos } 775 1.1 christos 776 1.1 christos return 0; 777 1.1 christos } 778 1.1 christos 779 1.1 christos 780 1.1 christos static int wpas_beacon_rep_add_frame_body(struct bitfield *eids, 781 1.1.1.3 christos struct bitfield *ext_eids, 782 1.1 christos enum beacon_report_detail detail, 783 1.1 christos struct wpa_bss *bss, u8 *buf, 784 1.1.1.3 christos size_t buf_len, const u8 **ies_buf, 785 1.1.1.2 christos size_t *ie_len, int add_fixed) 786 1.1 christos { 787 1.1.1.3 christos const u8 *ies = *ies_buf; 788 1.1.1.2 christos size_t ies_len = *ie_len; 789 1.1 christos u8 *pos = buf; 790 1.1 christos int rem_len; 791 1.1 christos 792 1.1 christos rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) - 793 1.1.1.2 christos sizeof(struct rrm_measurement_report_element) - 2 - 794 1.1.1.2 christos REPORTED_FRAME_BODY_SUBELEM_LEN; 795 1.1 christos 796 1.1 christos if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) { 797 1.1 christos wpa_printf(MSG_DEBUG, 798 1.1 christos "Beacon Request: Invalid reporting detail: %d", 799 1.1 christos detail); 800 1.1 christos return -1; 801 1.1 christos } 802 1.1 christos 803 1.1 christos if (detail == BEACON_REPORT_DETAIL_NONE) 804 1.1 christos return 0; 805 1.1 christos 806 1.1 christos /* 807 1.1 christos * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) + 808 1.1 christos * beacon interval(2) + capabilities(2) = 14 bytes 809 1.1 christos */ 810 1.1.1.2 christos if (add_fixed && buf_len < 14) 811 1.1.1.2 christos return -1; 812 1.1 christos 813 1.1 christos *pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY; 814 1.1 christos /* The length will be filled later */ 815 1.1 christos pos++; 816 1.1.1.2 christos 817 1.1.1.2 christos if (add_fixed) { 818 1.1.1.2 christos WPA_PUT_LE64(pos, bss->tsf); 819 1.1.1.2 christos pos += sizeof(bss->tsf); 820 1.1.1.2 christos WPA_PUT_LE16(pos, bss->beacon_int); 821 1.1.1.2 christos pos += 2; 822 1.1.1.2 christos WPA_PUT_LE16(pos, bss->caps); 823 1.1.1.2 christos pos += 2; 824 1.1.1.2 christos } 825 1.1 christos 826 1.1 christos rem_len -= pos - buf; 827 1.1 christos 828 1.1 christos /* 829 1.1 christos * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame 830 1.1 christos * body subelement causes the element to exceed the maximum element 831 1.1 christos * size, the subelement is truncated so that the last IE is a complete 832 1.1 christos * IE. So even when required to report all IEs, add elements one after 833 1.1 christos * the other and stop once there is no more room in the measurement 834 1.1 christos * element. 835 1.1 christos */ 836 1.1 christos while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) { 837 1.1 christos if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS || 838 1.1.1.3 christos (eids && bitfield_is_set(eids, ies[0])) || 839 1.1.1.3 christos (ext_eids && ies[0] == WLAN_EID_EXTENSION && ies[1] && 840 1.1.1.3 christos bitfield_is_set(ext_eids, ies[2]))) { 841 1.1.1.2 christos u8 elen = ies[1]; 842 1.1 christos 843 1.1 christos if (2 + elen > buf + buf_len - pos || 844 1.1 christos 2 + elen > rem_len) 845 1.1 christos break; 846 1.1 christos 847 1.1 christos *pos++ = ies[0]; 848 1.1 christos *pos++ = elen; 849 1.1 christos os_memcpy(pos, ies + 2, elen); 850 1.1 christos pos += elen; 851 1.1 christos rem_len -= 2 + elen; 852 1.1 christos } 853 1.1 christos 854 1.1 christos ies_len -= 2 + ies[1]; 855 1.1 christos ies += 2 + ies[1]; 856 1.1 christos } 857 1.1 christos 858 1.1.1.2 christos *ie_len = ies_len; 859 1.1.1.2 christos *ies_buf = ies; 860 1.1.1.2 christos 861 1.1 christos /* Now the length is known */ 862 1.1 christos buf[1] = pos - buf - 2; 863 1.1 christos return pos - buf; 864 1.1 christos } 865 1.1 christos 866 1.1 christos 867 1.1.1.2 christos static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data, 868 1.1.1.2 christos struct wpa_bss *bss, 869 1.1.1.2 christos struct wpabuf **wpa_buf, 870 1.1.1.2 christos struct rrm_measurement_beacon_report *rep, 871 1.1.1.3 christos const u8 **ie, size_t *ie_len, u8 idx) 872 1.1.1.2 christos { 873 1.1.1.2 christos int ret; 874 1.1.1.2 christos u8 *buf, *pos; 875 1.1.1.2 christos u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN + 876 1.1.1.2 christos (data->last_indication ? 877 1.1.1.2 christos BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0); 878 1.1.1.2 christos 879 1.1.1.2 christos /* Maximum element length: Beacon Report element + Reported Frame Body 880 1.1.1.2 christos * subelement + all IEs of the reported Beacon frame + Reported Frame 881 1.1.1.2 christos * Body Fragment ID subelement */ 882 1.1.1.2 christos buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len); 883 1.1.1.2 christos if (!buf) 884 1.1.1.2 christos return -1; 885 1.1.1.2 christos 886 1.1.1.2 christos os_memcpy(buf, rep, sizeof(*rep)); 887 1.1.1.2 christos 888 1.1.1.3 christos ret = wpas_beacon_rep_add_frame_body(data->eids, data->ext_eids, 889 1.1.1.3 christos data->report_detail, 890 1.1.1.2 christos bss, buf + sizeof(*rep), 891 1.1.1.2 christos 14 + *ie_len, ie, ie_len, 892 1.1.1.2 christos idx == 0); 893 1.1.1.2 christos if (ret < 0) 894 1.1.1.2 christos goto out; 895 1.1.1.2 christos 896 1.1.1.2 christos pos = buf + ret + sizeof(*rep); 897 1.1.1.2 christos pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID; 898 1.1.1.2 christos pos[1] = 2; 899 1.1.1.2 christos 900 1.1.1.2 christos /* 901 1.1.1.2 christos * Only one Beacon Report Measurement is supported at a time, so 902 1.1.1.2 christos * the Beacon Report ID can always be set to 1. 903 1.1.1.2 christos */ 904 1.1.1.2 christos pos[2] = 1; 905 1.1.1.2 christos 906 1.1.1.2 christos /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7) 907 1.1.1.2 christos */ 908 1.1.1.2 christos pos[3] = idx; 909 1.1.1.2 christos if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len) 910 1.1.1.2 christos pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS; 911 1.1.1.2 christos else 912 1.1.1.2 christos pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS; 913 1.1.1.2 christos 914 1.1.1.2 christos pos += REPORTED_FRAME_BODY_SUBELEM_LEN; 915 1.1.1.2 christos 916 1.1.1.2 christos if (data->last_indication) { 917 1.1.1.2 christos pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION; 918 1.1.1.2 christos pos[1] = 1; 919 1.1.1.2 christos 920 1.1.1.2 christos /* This field will be updated later if this is the last frame */ 921 1.1.1.2 christos pos[2] = 0; 922 1.1.1.2 christos } 923 1.1.1.2 christos 924 1.1.1.2 christos ret = wpas_rrm_report_elem(wpa_buf, data->token, 925 1.1.1.2 christos MEASUREMENT_REPORT_MODE_ACCEPT, 926 1.1.1.2 christos MEASURE_TYPE_BEACON, buf, 927 1.1.1.2 christos ret + sizeof(*rep) + subelems_len); 928 1.1.1.2 christos out: 929 1.1.1.2 christos os_free(buf); 930 1.1.1.2 christos return ret; 931 1.1.1.2 christos } 932 1.1.1.2 christos 933 1.1.1.2 christos 934 1.1 christos static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s, 935 1.1 christos struct wpabuf **wpa_buf, struct wpa_bss *bss, 936 1.1 christos u64 start, u64 parent_tsf) 937 1.1 christos { 938 1.1 christos struct beacon_rep_data *data = &wpa_s->beacon_rep_data; 939 1.1.1.3 christos const u8 *ies = wpa_bss_ie_ptr(bss); 940 1.1.1.3 christos const u8 *pos = ies; 941 1.1.1.2 christos size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; 942 1.1.1.2 christos struct rrm_measurement_beacon_report rep; 943 1.1.1.2 christos u8 idx = 0; 944 1.1 christos 945 1.1.1.3 christos if (!ether_addr_equal(data->bssid, broadcast_ether_addr) && 946 1.1.1.3 christos !ether_addr_equal(data->bssid, bss->bssid)) 947 1.1 christos return 0; 948 1.1 christos 949 1.1 christos if (data->ssid_len && 950 1.1 christos (data->ssid_len != bss->ssid_len || 951 1.1 christos os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0)) 952 1.1 christos return 0; 953 1.1 christos 954 1.1.1.2 christos if (wpas_get_op_chan_phy(bss->freq, ies, ies_len, &rep.op_class, 955 1.1.1.2 christos &rep.channel, &rep.report_info) < 0) 956 1.1.1.2 christos return 0; 957 1.1 christos 958 1.1.1.2 christos rep.start_time = host_to_le64(start); 959 1.1.1.2 christos rep.duration = host_to_le16(data->scan_params.duration); 960 1.1.1.2 christos rep.rcpi = rssi_to_rcpi(bss->level); 961 1.1.1.2 christos rep.rsni = 255; /* 255 indicates that RSNI is not available */ 962 1.1.1.2 christos os_memcpy(rep.bssid, bss->bssid, ETH_ALEN); 963 1.1.1.2 christos rep.antenna_id = 0; /* unknown */ 964 1.1.1.2 christos rep.parent_tsf = host_to_le32(parent_tsf); 965 1.1.1.2 christos 966 1.1.1.2 christos do { 967 1.1.1.2 christos int ret; 968 1.1.1.2 christos 969 1.1.1.2 christos ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep, 970 1.1.1.2 christos &pos, &ies_len, idx++); 971 1.1.1.2 christos if (ret) 972 1.1.1.2 christos return ret; 973 1.1.1.2 christos } while (data->report_detail != BEACON_REPORT_DETAIL_NONE && 974 1.1.1.2 christos ies_len >= 2); 975 1.1 christos 976 1.1.1.2 christos return 0; 977 1.1 christos } 978 1.1 christos 979 1.1 christos 980 1.1 christos static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s, 981 1.1 christos struct wpabuf **buf) 982 1.1 christos { 983 1.1 christos return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token, 984 1.1 christos MEASUREMENT_REPORT_MODE_ACCEPT, 985 1.1 christos MEASURE_TYPE_BEACON, NULL, 0); 986 1.1 christos } 987 1.1 christos 988 1.1 christos 989 1.1 christos static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s, 990 1.1 christos struct wpabuf **buf) 991 1.1 christos { 992 1.1 christos size_t i; 993 1.1 christos 994 1.1 christos for (i = 0; i < wpa_s->last_scan_res_used; i++) { 995 1.1 christos if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i], 996 1.1 christos 0, 0) < 0) 997 1.1 christos break; 998 1.1 christos } 999 1.1 christos 1000 1.1 christos if (!(*buf)) 1001 1.1 christos wpas_beacon_rep_no_results(wpa_s, buf); 1002 1.1 christos 1003 1.1 christos wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf); 1004 1.1 christos } 1005 1.1 christos 1006 1.1 christos 1007 1.1 christos void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s) 1008 1.1 christos { 1009 1.1 christos if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) { 1010 1.1 christos struct wpabuf *buf = NULL; 1011 1.1 christos 1012 1.1 christos if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token, 1013 1.1 christos MEASUREMENT_REPORT_MODE_REJECT_REFUSED, 1014 1.1 christos MEASURE_TYPE_BEACON, NULL, 0)) { 1015 1.1 christos wpa_printf(MSG_ERROR, "RRM: Memory allocation failed"); 1016 1.1 christos wpabuf_free(buf); 1017 1.1 christos return; 1018 1.1 christos } 1019 1.1 christos 1020 1.1 christos wpas_rrm_send_msr_report(wpa_s, buf); 1021 1.1 christos wpabuf_free(buf); 1022 1.1 christos } 1023 1.1 christos 1024 1.1 christos wpas_clear_beacon_rep_data(wpa_s); 1025 1.1 christos } 1026 1.1 christos 1027 1.1 christos 1028 1.1 christos static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx) 1029 1.1 christos { 1030 1.1 christos struct wpa_supplicant *wpa_s = eloop_ctx; 1031 1.1 christos struct wpa_driver_scan_params *params = 1032 1.1 christos &wpa_s->beacon_rep_data.scan_params; 1033 1.1 christos u16 prev_duration = params->duration; 1034 1.1 christos 1035 1.1 christos if (!wpa_s->current_bss) 1036 1.1 christos return; 1037 1.1 christos 1038 1.1 christos if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) && 1039 1.1 christos params->duration) { 1040 1.1 christos wpa_printf(MSG_DEBUG, 1041 1.1 christos "RRM: Cannot set scan duration due to missing driver support"); 1042 1.1 christos params->duration = 0; 1043 1.1 christos } 1044 1.1 christos os_get_reltime(&wpa_s->beacon_rep_scan); 1045 1.1 christos if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) || 1046 1.1.1.3 christos wpa_supplicant_trigger_scan(wpa_s, params, true, false)) 1047 1.1 christos wpas_rrm_refuse_request(wpa_s); 1048 1.1 christos params->duration = prev_duration; 1049 1.1 christos } 1050 1.1 christos 1051 1.1 christos 1052 1.1 christos static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s, 1053 1.1 christos struct beacon_rep_data *data, 1054 1.1 christos u8 sid, u8 slen, const u8 *subelem) 1055 1.1 christos { 1056 1.1.1.3 christos struct bitfield *eids; 1057 1.1 christos u8 report_info, i; 1058 1.1 christos 1059 1.1 christos switch (sid) { 1060 1.1 christos case WLAN_BEACON_REQUEST_SUBELEM_SSID: 1061 1.1 christos if (!slen) { 1062 1.1 christos wpa_printf(MSG_DEBUG, 1063 1.1 christos "SSID subelement with zero length - wildcard SSID"); 1064 1.1 christos break; 1065 1.1 christos } 1066 1.1 christos 1067 1.1 christos if (slen > SSID_MAX_LEN) { 1068 1.1 christos wpa_printf(MSG_DEBUG, 1069 1.1 christos "Invalid SSID subelement length: %u", slen); 1070 1.1 christos return -1; 1071 1.1 christos } 1072 1.1 christos 1073 1.1 christos data->ssid_len = slen; 1074 1.1 christos os_memcpy(data->ssid, subelem, data->ssid_len); 1075 1.1 christos break; 1076 1.1 christos case WLAN_BEACON_REQUEST_SUBELEM_INFO: 1077 1.1 christos if (slen != 2) { 1078 1.1 christos wpa_printf(MSG_DEBUG, 1079 1.1 christos "Invalid reporting information subelement length: %u", 1080 1.1 christos slen); 1081 1.1 christos return -1; 1082 1.1 christos } 1083 1.1 christos 1084 1.1 christos report_info = subelem[0]; 1085 1.1 christos if (report_info != 0) { 1086 1.1 christos wpa_printf(MSG_DEBUG, 1087 1.1 christos "reporting information=%u is not supported", 1088 1.1 christos report_info); 1089 1.1 christos return 0; 1090 1.1 christos } 1091 1.1 christos break; 1092 1.1 christos case WLAN_BEACON_REQUEST_SUBELEM_DETAIL: 1093 1.1 christos if (slen != 1) { 1094 1.1 christos wpa_printf(MSG_DEBUG, 1095 1.1 christos "Invalid reporting detail subelement length: %u", 1096 1.1 christos slen); 1097 1.1 christos return -1; 1098 1.1 christos } 1099 1.1 christos 1100 1.1 christos data->report_detail = subelem[0]; 1101 1.1 christos if (data->report_detail > 1102 1.1 christos BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) { 1103 1.1 christos wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u", 1104 1.1 christos subelem[0]); 1105 1.1 christos return -1; 1106 1.1 christos } 1107 1.1 christos 1108 1.1 christos break; 1109 1.1 christos case WLAN_BEACON_REQUEST_SUBELEM_REQUEST: 1110 1.1.1.3 christos case WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST: 1111 1.1 christos if (data->report_detail != 1112 1.1 christos BEACON_REPORT_DETAIL_REQUESTED_ONLY) { 1113 1.1 christos wpa_printf(MSG_DEBUG, 1114 1.1 christos "Beacon request: request subelement is present but report detail is %u", 1115 1.1 christos data->report_detail); 1116 1.1 christos return -1; 1117 1.1 christos } 1118 1.1 christos 1119 1.1 christos if (!slen) { 1120 1.1 christos wpa_printf(MSG_DEBUG, 1121 1.1 christos "Invalid request subelement length: %u", 1122 1.1 christos slen); 1123 1.1 christos return -1; 1124 1.1 christos } 1125 1.1 christos 1126 1.1.1.3 christos if (sid == WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST) { 1127 1.1.1.3 christos if (slen < 2) { 1128 1.1.1.3 christos wpa_printf(MSG_DEBUG, 1129 1.1.1.3 christos "Invalid extended request"); 1130 1.1.1.3 christos return -1; 1131 1.1.1.3 christos } 1132 1.1.1.3 christos if (subelem[0] != WLAN_EID_EXTENSION) { 1133 1.1.1.3 christos wpa_printf(MSG_DEBUG, 1134 1.1.1.3 christos "Skip unknown Requested Element ID %u in Extended Request subelement", 1135 1.1.1.3 christos subelem[0]); 1136 1.1.1.3 christos break; 1137 1.1.1.3 christos } 1138 1.1.1.3 christos 1139 1.1.1.3 christos /* Skip the Requested Element ID field */ 1140 1.1.1.3 christos subelem++; 1141 1.1.1.3 christos slen--; 1142 1.1.1.3 christos } 1143 1.1.1.3 christos 1144 1.1.1.3 christos if ((sid == WLAN_BEACON_REQUEST_SUBELEM_REQUEST && 1145 1.1.1.3 christos data->eids) || 1146 1.1.1.3 christos (sid == WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST && 1147 1.1.1.3 christos data->ext_eids)) { 1148 1.1 christos wpa_printf(MSG_DEBUG, 1149 1.1.1.3 christos "Beacon Request: Request sub elements appear more than once"); 1150 1.1 christos return -1; 1151 1.1 christos } 1152 1.1 christos 1153 1.1.1.3 christos eids = bitfield_alloc(255); 1154 1.1.1.3 christos if (!eids) { 1155 1.1 christos wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap"); 1156 1.1 christos return -1; 1157 1.1 christos } 1158 1.1 christos 1159 1.1.1.3 christos if (sid == WLAN_BEACON_REQUEST_SUBELEM_REQUEST) 1160 1.1.1.3 christos data->eids = eids; 1161 1.1.1.3 christos else 1162 1.1.1.3 christos data->ext_eids = eids; 1163 1.1.1.3 christos 1164 1.1 christos for (i = 0; i < slen; i++) 1165 1.1.1.3 christos bitfield_set(eids, subelem[i]); 1166 1.1 christos break; 1167 1.1 christos case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL: 1168 1.1 christos /* Skip - it will be processed when freqs are added */ 1169 1.1 christos break; 1170 1.1.1.2 christos case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION: 1171 1.1.1.2 christos if (slen != 1) { 1172 1.1.1.2 christos wpa_printf(MSG_DEBUG, 1173 1.1.1.2 christos "Beacon request: Invalid last indication request subelement length: %u", 1174 1.1.1.2 christos slen); 1175 1.1.1.2 christos return -1; 1176 1.1.1.2 christos } 1177 1.1.1.2 christos 1178 1.1.1.2 christos data->last_indication = subelem[0]; 1179 1.1.1.2 christos break; 1180 1.1 christos default: 1181 1.1 christos wpa_printf(MSG_DEBUG, 1182 1.1 christos "Beacon request: Unknown subelement id %u", sid); 1183 1.1 christos break; 1184 1.1 christos } 1185 1.1 christos 1186 1.1 christos return 1; 1187 1.1 christos } 1188 1.1 christos 1189 1.1 christos 1190 1.1 christos /** 1191 1.1 christos * Returns 0 if the next element can be processed, 1 if some operation was 1192 1.1 christos * triggered, and -1 if processing failed (i.e., the element is in invalid 1193 1.1 christos * format or an internal error occurred). 1194 1.1 christos */ 1195 1.1 christos static int 1196 1.1 christos wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s, 1197 1.1 christos u8 elem_token, int duration_mandatory, 1198 1.1 christos const struct rrm_measurement_beacon_request *req, 1199 1.1 christos size_t len, struct wpabuf **buf) 1200 1.1 christos { 1201 1.1 christos struct beacon_rep_data *data = &wpa_s->beacon_rep_data; 1202 1.1 christos struct wpa_driver_scan_params *params = &data->scan_params; 1203 1.1 christos const u8 *subelems; 1204 1.1 christos size_t elems_len; 1205 1.1 christos u16 rand_interval; 1206 1.1 christos u32 interval_usec; 1207 1.1 christos u32 _rand; 1208 1.1 christos int ret = 0, res; 1209 1.1 christos u8 reject_mode; 1210 1.1 christos 1211 1.1 christos if (len < sizeof(*req)) 1212 1.1 christos return -1; 1213 1.1 christos 1214 1.1 christos if (req->mode != BEACON_REPORT_MODE_PASSIVE && 1215 1.1 christos req->mode != BEACON_REPORT_MODE_ACTIVE && 1216 1.1 christos req->mode != BEACON_REPORT_MODE_TABLE) 1217 1.1 christos return 0; 1218 1.1 christos 1219 1.1 christos subelems = req->variable; 1220 1.1 christos elems_len = len - sizeof(*req); 1221 1.1 christos rand_interval = le_to_host16(req->rand_interval); 1222 1.1 christos 1223 1.1 christos os_free(params->freqs); 1224 1.1 christos os_memset(params, 0, sizeof(*params)); 1225 1.1 christos 1226 1.1 christos data->token = elem_token; 1227 1.1 christos 1228 1.1 christos /* default reporting detail is all fixed length fields and all 1229 1.1 christos * elements */ 1230 1.1 christos data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS; 1231 1.1 christos os_memcpy(data->bssid, req->bssid, ETH_ALEN); 1232 1.1 christos 1233 1.1 christos while (elems_len >= 2) { 1234 1.1 christos if (subelems[1] > elems_len - 2) { 1235 1.1 christos wpa_printf(MSG_DEBUG, 1236 1.1 christos "Beacon Request: Truncated subelement"); 1237 1.1 christos ret = -1; 1238 1.1 christos goto out; 1239 1.1 christos } 1240 1.1 christos 1241 1.1 christos res = wpas_rm_handle_beacon_req_subelem( 1242 1.1 christos wpa_s, data, subelems[0], subelems[1], &subelems[2]); 1243 1.1 christos if (res < 0) { 1244 1.1 christos ret = res; 1245 1.1 christos goto out; 1246 1.1 christos } else if (!res) { 1247 1.1 christos reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE; 1248 1.1 christos goto out_reject; 1249 1.1 christos } 1250 1.1 christos 1251 1.1 christos elems_len -= 2 + subelems[1]; 1252 1.1 christos subelems += 2 + subelems[1]; 1253 1.1 christos } 1254 1.1 christos 1255 1.1 christos if (req->mode == BEACON_REPORT_MODE_TABLE) { 1256 1.1 christos wpas_beacon_rep_table(wpa_s, buf); 1257 1.1 christos goto out; 1258 1.1 christos } 1259 1.1 christos 1260 1.1.1.3 christos params->freqs = wpas_beacon_request_freqs(wpa_s, req->oper_class, 1261 1.1.1.3 christos req->channel, req->variable, 1262 1.1.1.3 christos len - sizeof(*req)); 1263 1.1 christos if (!params->freqs) { 1264 1.1 christos wpa_printf(MSG_DEBUG, "Beacon request: No valid channels"); 1265 1.1 christos reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED; 1266 1.1 christos goto out_reject; 1267 1.1 christos } 1268 1.1 christos 1269 1.1 christos params->duration = le_to_host16(req->duration); 1270 1.1 christos params->duration_mandatory = duration_mandatory; 1271 1.1 christos if (!params->duration) { 1272 1.1 christos wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0"); 1273 1.1 christos ret = -1; 1274 1.1 christos goto out; 1275 1.1 christos } 1276 1.1 christos 1277 1.1 christos params->only_new_results = 1; 1278 1.1 christos 1279 1.1 christos if (req->mode == BEACON_REPORT_MODE_ACTIVE) { 1280 1.1 christos params->ssids[params->num_ssids].ssid = data->ssid; 1281 1.1 christos params->ssids[params->num_ssids++].ssid_len = data->ssid_len; 1282 1.1 christos } 1283 1.1 christos 1284 1.1 christos if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) 1285 1.1 christos _rand = os_random(); 1286 1.1 christos interval_usec = (_rand % (rand_interval + 1)) * 1024; 1287 1.1 christos eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s, 1288 1.1 christos NULL); 1289 1.1 christos return 1; 1290 1.1 christos out_reject: 1291 1.1 christos if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && 1292 1.1 christos wpas_rrm_report_elem(buf, elem_token, reject_mode, 1293 1.1 christos MEASURE_TYPE_BEACON, NULL, 0) < 0) { 1294 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); 1295 1.1 christos ret = -1; 1296 1.1 christos } 1297 1.1 christos out: 1298 1.1 christos wpas_clear_beacon_rep_data(wpa_s); 1299 1.1 christos return ret; 1300 1.1 christos } 1301 1.1 christos 1302 1.1 christos 1303 1.1 christos static int 1304 1.1 christos wpas_rrm_handle_msr_req_element( 1305 1.1 christos struct wpa_supplicant *wpa_s, 1306 1.1 christos const struct rrm_measurement_request_element *req, 1307 1.1 christos struct wpabuf **buf) 1308 1.1 christos { 1309 1.1 christos int duration_mandatory; 1310 1.1 christos 1311 1.1 christos wpa_printf(MSG_DEBUG, "Measurement request type %d token %d", 1312 1.1 christos req->type, req->token); 1313 1.1 christos 1314 1.1 christos if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) { 1315 1.1 christos /* Enable bit is not supported for now */ 1316 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore"); 1317 1.1 christos return 0; 1318 1.1 christos } 1319 1.1 christos 1320 1.1 christos if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) && 1321 1.1 christos req->type > MEASURE_TYPE_RPI_HIST) { 1322 1.1 christos /* Parallel measurements are not supported for now */ 1323 1.1 christos wpa_printf(MSG_DEBUG, 1324 1.1 christos "RRM: Parallel measurements are not supported, reject"); 1325 1.1 christos goto reject; 1326 1.1 christos } 1327 1.1 christos 1328 1.1 christos duration_mandatory = 1329 1.1 christos !!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY); 1330 1.1 christos 1331 1.1 christos switch (req->type) { 1332 1.1 christos case MEASURE_TYPE_LCI: 1333 1.1 christos return wpas_rrm_build_lci_report(wpa_s, req, buf); 1334 1.1 christos case MEASURE_TYPE_BEACON: 1335 1.1 christos if (duration_mandatory && 1336 1.1 christos !(wpa_s->drv_rrm_flags & 1337 1.1 christos WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL)) { 1338 1.1 christos wpa_printf(MSG_DEBUG, 1339 1.1 christos "RRM: Driver does not support dwell time configuration - reject beacon report with mandatory duration"); 1340 1.1 christos goto reject; 1341 1.1 christos } 1342 1.1 christos return wpas_rm_handle_beacon_req(wpa_s, req->token, 1343 1.1 christos duration_mandatory, 1344 1.1 christos (const void *) req->variable, 1345 1.1 christos req->len - 3, buf); 1346 1.1 christos default: 1347 1.1 christos wpa_printf(MSG_INFO, 1348 1.1 christos "RRM: Unsupported radio measurement type %u", 1349 1.1 christos req->type); 1350 1.1 christos break; 1351 1.1 christos } 1352 1.1 christos 1353 1.1 christos reject: 1354 1.1 christos if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && 1355 1.1 christos wpas_rrm_report_elem(buf, req->token, 1356 1.1 christos MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE, 1357 1.1 christos req->type, NULL, 0) < 0) { 1358 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); 1359 1.1 christos return -1; 1360 1.1 christos } 1361 1.1 christos 1362 1.1 christos return 0; 1363 1.1 christos } 1364 1.1 christos 1365 1.1 christos 1366 1.1 christos static struct wpabuf * 1367 1.1 christos wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos, 1368 1.1 christos size_t len) 1369 1.1 christos { 1370 1.1 christos struct wpabuf *buf = NULL; 1371 1.1 christos 1372 1.1 christos while (len) { 1373 1.1 christos const struct rrm_measurement_request_element *req; 1374 1.1 christos int res; 1375 1.1 christos 1376 1.1 christos if (len < 2) { 1377 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Truncated element"); 1378 1.1 christos goto out; 1379 1.1 christos } 1380 1.1 christos 1381 1.1 christos req = (const struct rrm_measurement_request_element *) pos; 1382 1.1 christos if (req->eid != WLAN_EID_MEASURE_REQUEST) { 1383 1.1 christos wpa_printf(MSG_DEBUG, 1384 1.1 christos "RRM: Expected Measurement Request element, but EID is %u", 1385 1.1 christos req->eid); 1386 1.1 christos goto out; 1387 1.1 christos } 1388 1.1 christos 1389 1.1 christos if (req->len < 3) { 1390 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Element length too short"); 1391 1.1 christos goto out; 1392 1.1 christos } 1393 1.1 christos 1394 1.1 christos if (req->len > len - 2) { 1395 1.1 christos wpa_printf(MSG_DEBUG, "RRM: Element length too long"); 1396 1.1 christos goto out; 1397 1.1 christos } 1398 1.1 christos 1399 1.1 christos res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf); 1400 1.1 christos if (res < 0) 1401 1.1 christos goto out; 1402 1.1 christos 1403 1.1 christos pos += req->len + 2; 1404 1.1 christos len -= req->len + 2; 1405 1.1 christos } 1406 1.1 christos 1407 1.1 christos return buf; 1408 1.1 christos 1409 1.1 christos out: 1410 1.1 christos wpabuf_free(buf); 1411 1.1 christos return NULL; 1412 1.1 christos } 1413 1.1 christos 1414 1.1 christos 1415 1.1 christos void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, 1416 1.1 christos const u8 *src, const u8 *dst, 1417 1.1 christos const u8 *frame, size_t len) 1418 1.1 christos { 1419 1.1 christos struct wpabuf *report; 1420 1.1 christos 1421 1.1 christos if (wpa_s->wpa_state != WPA_COMPLETED) { 1422 1.1 christos wpa_printf(MSG_INFO, 1423 1.1 christos "RRM: Ignoring radio measurement request: Not associated"); 1424 1.1 christos return; 1425 1.1 christos } 1426 1.1 christos 1427 1.1 christos if (!wpa_s->rrm.rrm_used) { 1428 1.1 christos wpa_printf(MSG_INFO, 1429 1.1 christos "RRM: Ignoring radio measurement request: Not RRM network"); 1430 1.1 christos return; 1431 1.1 christos } 1432 1.1 christos 1433 1.1 christos if (len < 3) { 1434 1.1 christos wpa_printf(MSG_INFO, 1435 1.1 christos "RRM: Ignoring too short radio measurement request"); 1436 1.1 christos return; 1437 1.1 christos } 1438 1.1 christos 1439 1.1 christos wpa_s->rrm.token = *frame; 1440 1.1 christos os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN); 1441 1.1 christos 1442 1.1 christos /* Number of repetitions is not supported */ 1443 1.1 christos 1444 1.1 christos report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3); 1445 1.1 christos if (!report) 1446 1.1 christos return; 1447 1.1 christos 1448 1.1 christos wpas_rrm_send_msr_report(wpa_s, report); 1449 1.1 christos wpabuf_free(report); 1450 1.1 christos } 1451 1.1 christos 1452 1.1 christos 1453 1.1 christos void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, 1454 1.1 christos const u8 *src, 1455 1.1 christos const u8 *frame, size_t len, 1456 1.1 christos int rssi) 1457 1.1 christos { 1458 1.1 christos struct wpabuf *buf; 1459 1.1 christos const struct rrm_link_measurement_request *req; 1460 1.1 christos struct rrm_link_measurement_report report; 1461 1.1 christos 1462 1.1 christos if (wpa_s->wpa_state != WPA_COMPLETED) { 1463 1.1 christos wpa_printf(MSG_INFO, 1464 1.1 christos "RRM: Ignoring link measurement request. Not associated"); 1465 1.1 christos return; 1466 1.1 christos } 1467 1.1 christos 1468 1.1 christos if (!wpa_s->rrm.rrm_used) { 1469 1.1 christos wpa_printf(MSG_INFO, 1470 1.1 christos "RRM: Ignoring link measurement request. Not RRM network"); 1471 1.1 christos return; 1472 1.1 christos } 1473 1.1 christos 1474 1.1 christos if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { 1475 1.1 christos wpa_printf(MSG_INFO, 1476 1.1 christos "RRM: Measurement report failed. TX power insertion not supported"); 1477 1.1 christos return; 1478 1.1 christos } 1479 1.1 christos 1480 1.1 christos req = (const struct rrm_link_measurement_request *) frame; 1481 1.1 christos if (len < sizeof(*req)) { 1482 1.1 christos wpa_printf(MSG_INFO, 1483 1.1 christos "RRM: Link measurement report failed. Request too short"); 1484 1.1 christos return; 1485 1.1 christos } 1486 1.1 christos 1487 1.1 christos os_memset(&report, 0, sizeof(report)); 1488 1.1 christos report.dialog_token = req->dialog_token; 1489 1.1 christos report.tpc.eid = WLAN_EID_TPC_REPORT; 1490 1.1 christos report.tpc.len = 2; 1491 1.1 christos /* Note: The driver is expected to update report.tpc.tx_power and 1492 1.1 christos * report.tpc.link_margin subfields when sending out this frame. 1493 1.1 christos * Similarly, the driver would need to update report.rx_ant_id and 1494 1.1 christos * report.tx_ant_id subfields. */ 1495 1.1 christos report.rsni = 255; /* 255 indicates that RSNI is not available */ 1496 1.1 christos report.rcpi = rssi_to_rcpi(rssi); 1497 1.1 christos 1498 1.1 christos /* action_category + action_code */ 1499 1.1 christos buf = wpabuf_alloc(2 + sizeof(report)); 1500 1.1 christos if (buf == NULL) { 1501 1.1 christos wpa_printf(MSG_ERROR, 1502 1.1 christos "RRM: Link measurement report failed. Buffer allocation failed"); 1503 1.1 christos return; 1504 1.1 christos } 1505 1.1 christos 1506 1.1 christos wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 1507 1.1 christos wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT); 1508 1.1 christos wpabuf_put_data(buf, &report, sizeof(report)); 1509 1.1 christos wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf); 1510 1.1 christos 1511 1.1 christos if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src, 1512 1.1 christos wpa_s->own_addr, wpa_s->bssid, 1513 1.1 christos wpabuf_head(buf), wpabuf_len(buf), 0)) { 1514 1.1 christos wpa_printf(MSG_ERROR, 1515 1.1 christos "RRM: Link measurement report failed. Send action failed"); 1516 1.1 christos } 1517 1.1 christos wpabuf_free(buf); 1518 1.1 christos } 1519 1.1 christos 1520 1.1 christos 1521 1.1.1.3 christos static bool wpas_beacon_rep_scan_match(struct wpa_supplicant *wpa_s, 1522 1.1.1.3 christos const u8 *bssid) 1523 1.1.1.3 christos { 1524 1.1.1.3 christos u8 i; 1525 1.1.1.3 christos 1526 1.1.1.3 christos if (!wpa_s->valid_links) 1527 1.1.1.3 christos return ether_addr_equal(wpa_s->current_bss->bssid, bssid); 1528 1.1.1.3 christos 1529 1.1.1.3 christos for_each_link(wpa_s->valid_links, i) { 1530 1.1.1.3 christos if (ether_addr_equal(wpa_s->links[i].bssid, bssid)) 1531 1.1.1.3 christos return true; 1532 1.1.1.3 christos } 1533 1.1.1.3 christos 1534 1.1.1.3 christos wpa_printf(MSG_DEBUG, "RRM: MLD: no match for TSF BSSID=" MACSTR, 1535 1.1.1.3 christos MAC2STR(bssid)); 1536 1.1.1.3 christos 1537 1.1.1.3 christos return false; 1538 1.1.1.3 christos } 1539 1.1.1.3 christos 1540 1.1.1.3 christos 1541 1.1 christos int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, 1542 1.1 christos struct wpa_scan_results *scan_res, 1543 1.1 christos struct scan_info *info) 1544 1.1 christos { 1545 1.1 christos size_t i = 0; 1546 1.1 christos struct wpabuf *buf = NULL; 1547 1.1 christos 1548 1.1 christos if (!wpa_s->beacon_rep_data.token) 1549 1.1 christos return 0; 1550 1.1 christos 1551 1.1 christos if (!wpa_s->current_bss) 1552 1.1 christos goto out; 1553 1.1 christos 1554 1.1 christos /* If the measurement was aborted, don't report partial results */ 1555 1.1 christos if (info->aborted) 1556 1.1 christos goto out; 1557 1.1 christos 1558 1.1 christos wpa_printf(MSG_DEBUG, "RRM: TSF BSSID: " MACSTR " current BSS: " MACSTR, 1559 1.1 christos MAC2STR(info->scan_start_tsf_bssid), 1560 1.1 christos MAC2STR(wpa_s->current_bss->bssid)); 1561 1.1 christos if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && 1562 1.1.1.3 christos !wpas_beacon_rep_scan_match(wpa_s, info->scan_start_tsf_bssid)) { 1563 1.1 christos wpa_printf(MSG_DEBUG, 1564 1.1 christos "RRM: Ignore scan results due to mismatching TSF BSSID"); 1565 1.1 christos goto out; 1566 1.1 christos } 1567 1.1 christos 1568 1.1 christos for (i = 0; i < scan_res->num; i++) { 1569 1.1 christos struct wpa_bss *bss = 1570 1.1 christos wpa_bss_get_bssid(wpa_s, scan_res->res[i]->bssid); 1571 1.1 christos 1572 1.1 christos if (!bss) 1573 1.1 christos continue; 1574 1.1 christos 1575 1.1 christos if ((wpa_s->drv_rrm_flags & 1576 1.1 christos WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && 1577 1.1.1.3 christos !wpas_beacon_rep_scan_match(wpa_s, 1578 1.1.1.3 christos scan_res->res[i]->tsf_bssid)) { 1579 1.1 christos wpa_printf(MSG_DEBUG, 1580 1.1 christos "RRM: Ignore scan result for " MACSTR 1581 1.1 christos " due to mismatching TSF BSSID" MACSTR, 1582 1.1 christos MAC2STR(scan_res->res[i]->bssid), 1583 1.1 christos MAC2STR(scan_res->res[i]->tsf_bssid)); 1584 1.1 christos continue; 1585 1.1 christos } 1586 1.1 christos 1587 1.1 christos /* 1588 1.1 christos * Don't report results that were not received during the 1589 1.1 christos * current measurement. 1590 1.1 christos */ 1591 1.1 christos if (!(wpa_s->drv_rrm_flags & 1592 1.1 christos WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) { 1593 1.1 christos struct os_reltime update_time, diff; 1594 1.1 christos 1595 1.1 christos /* For now, allow 8 ms older results due to some 1596 1.1 christos * unknown issue with cfg80211 BSS table updates during 1597 1.1 christos * a scan with the current BSS. 1598 1.1 christos * TODO: Fix this more properly to avoid having to have 1599 1.1 christos * this type of hacks in place. */ 1600 1.1 christos calculate_update_time(&scan_res->fetch_time, 1601 1.1 christos scan_res->res[i]->age, 1602 1.1 christos &update_time); 1603 1.1 christos os_reltime_sub(&wpa_s->beacon_rep_scan, 1604 1.1 christos &update_time, &diff); 1605 1.1 christos if (os_reltime_before(&update_time, 1606 1.1 christos &wpa_s->beacon_rep_scan) && 1607 1.1 christos (diff.sec || diff.usec >= 8000)) { 1608 1.1 christos wpa_printf(MSG_DEBUG, 1609 1.1 christos "RRM: Ignore scan result for " MACSTR 1610 1.1 christos " due to old update (age(ms) %u, calculated age %u.%06u seconds)", 1611 1.1 christos MAC2STR(scan_res->res[i]->bssid), 1612 1.1 christos scan_res->res[i]->age, 1613 1.1 christos (unsigned int) diff.sec, 1614 1.1 christos (unsigned int) diff.usec); 1615 1.1 christos continue; 1616 1.1 christos } 1617 1.1 christos } else if (info->scan_start_tsf > 1618 1.1 christos scan_res->res[i]->parent_tsf) { 1619 1.1 christos continue; 1620 1.1 christos } 1621 1.1 christos 1622 1.1 christos if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf, 1623 1.1 christos scan_res->res[i]->parent_tsf) < 0) 1624 1.1 christos break; 1625 1.1 christos } 1626 1.1 christos 1627 1.1 christos if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf)) 1628 1.1 christos goto out; 1629 1.1 christos 1630 1.1 christos wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf); 1631 1.1 christos 1632 1.1 christos wpas_rrm_send_msr_report(wpa_s, buf); 1633 1.1 christos wpabuf_free(buf); 1634 1.1 christos 1635 1.1 christos out: 1636 1.1 christos wpas_clear_beacon_rep_data(wpa_s); 1637 1.1 christos return 1; 1638 1.1 christos } 1639 1.1 christos 1640 1.1 christos 1641 1.1 christos void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s) 1642 1.1 christos { 1643 1.1 christos struct beacon_rep_data *data = &wpa_s->beacon_rep_data; 1644 1.1 christos 1645 1.1 christos eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL); 1646 1.1 christos bitfield_free(data->eids); 1647 1.1.1.3 christos bitfield_free(data->ext_eids); 1648 1.1 christos os_free(data->scan_params.freqs); 1649 1.1 christos os_memset(data, 0, sizeof(*data)); 1650 1.1 christos } 1651