1 /*
2 * wpa_supplicant - Radio Measurements
3 * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/bitfield.h"
13 #include "common/ieee802_11_defs.h"
14 #include "common/ieee802_11_common.h"
15 #include "wpa_supplicant_i.h"
16 #include "bss.h"
17 #include "rrm.h"
18 #include "scan.h"
19 #include <sys/errno.h>
20 #ifdef ESP_SUPPLICANT
21 #include "esp_common_i.h"
22 #endif
23
wpas_rrm_neighbor_rep_timeout_handler(void * data,void * user_ctx)24 static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
25 {
26 struct rrm_data *rrm = data;
27
28 if (!rrm->notify_neighbor_rep) {
29 wpa_printf(MSG_ERROR,
30 "RRM: Unexpected neighbor report timeout");
31 return;
32 }
33
34 wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
35 rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL, 0);
36
37 rrm->notify_neighbor_rep = NULL;
38 rrm->neighbor_rep_cb_ctx = NULL;
39 }
40
41
42 /*
43 * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
44 * @wpa_s: Pointer to wpa_supplicant
45 */
wpas_rrm_reset(struct wpa_supplicant * wpa_s)46 void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
47 {
48 wpa_s->rrm.rrm_used = 0;
49
50 eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
51 NULL);
52 if (wpa_s->rrm.notify_neighbor_rep)
53 wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
54 wpa_s->rrm.next_neighbor_rep_token = 1;
55 wpas_clear_beacon_rep_data(wpa_s);
56 }
57
58
59 /*
60 * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
61 * @wpa_s: Pointer to wpa_supplicant
62 * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
63 * @report_len: Length of neighbor report buffer
64 */
wpas_rrm_process_neighbor_rep(struct wpa_supplicant * wpa_s,const u8 * report,size_t report_len)65 void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
66 const u8 *report, size_t report_len)
67 {
68
69 wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
70 if (report_len < 1)
71 return;
72
73 if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
74 wpa_printf(MSG_DEBUG,
75 "RRM: Discarding neighbor report with token %d (expected %d)",
76 report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
77 return;
78 }
79
80 eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
81 NULL);
82
83 if (!wpa_s->rrm.notify_neighbor_rep) {
84 wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
85 return;
86 }
87
88 wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
89 report[0]);
90 wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
91 report, report_len);
92 wpa_s->rrm.notify_neighbor_rep = NULL;
93 wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
94 }
95
96
97 #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
98 /* Workaround different, undefined for Windows, error codes used here */
99 #ifndef ENOTCONN
100 #define ENOTCONN -1
101 #endif
102 #ifndef EOPNOTSUPP
103 #define EOPNOTSUPP -1
104 #endif
105 #ifndef ECANCELED
106 #define ECANCELED -1
107 #endif
108 #endif
109
110 /* Measurement Request element + Location Subject + Maximum Age subelement */
111 #define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
112 /* Measurement Request element + Location Civic Request */
113 #define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
114
115
116 /**
117 * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
118 * @wpa_s: Pointer to wpa_supplicant
119 * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
120 * is sent in the request.
121 * @lci: if set, neighbor request will include LCI request
122 * @civic: if set, neighbor request will include civic location request
123 * @cb: Callback function to be called once the requested report arrives, or
124 * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
125 * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
126 * the requester's responsibility to free it.
127 * In the latter case NULL will be sent in 'neighbor_rep'.
128 * @cb_ctx: Context value to send the callback function
129 * Returns: 0 in case of success, negative error code otherwise
130 *
131 * In case there is a previous request which has not been answered yet, the
132 * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
133 * Request must contain a callback function.
134 */
wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant * wpa_s,const struct wpa_ssid_value * ssid,int lci,int civic,void (* cb)(void * ctx,const u8 * neighbor_rep,size_t len),void * cb_ctx)135 int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
136 const struct wpa_ssid_value *ssid,
137 int lci, int civic,
138 void (*cb)(void *ctx,
139 const u8 *neighbor_rep, size_t len),
140 void *cb_ctx)
141 {
142 struct wpabuf *buf;
143
144 if (!(wpa_s->rrm_ie[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
145 wpa_printf(MSG_ERROR,
146 "RRM: No network support for Neighbor Report.");
147 return -EOPNOTSUPP;
148 }
149
150 /* Refuse if there's a live request */
151 if (wpa_s->rrm.notify_neighbor_rep) {
152 wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
153 #if 0
154 wpa_dbg(wpa_s, MSG_DEBUG,
155 "RRM: Currently handling previous Neighbor Report.");
156 return -EBUSY;
157 #endif
158 }
159
160 /* 3 = action category + action code + dialog token */
161 buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
162 (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
163 (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
164 if (buf == NULL) {
165 wpa_dbg(wpa_s, MSG_DEBUG,
166 "RRM: Failed to allocate Neighbor Report Request");
167 return -ENOMEM;
168 }
169
170 wpa_dbg(wpa_s, MSG_DEBUG,
171 "RRM: Neighbor report request (for %s), token=%d",
172 (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
173 wpa_s->rrm.next_neighbor_rep_token);
174
175 wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
176 wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
177 wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
178 if (ssid) {
179 wpabuf_put_u8(buf, WLAN_EID_SSID);
180 wpabuf_put_u8(buf, ssid->ssid_len);
181 wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
182 }
183
184 if (lci) {
185 /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
186 wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
187 wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
188
189 /*
190 * Measurement token; nonzero number that is unique among the
191 * Measurement Request elements in a particular frame.
192 */
193 wpabuf_put_u8(buf, 1); /* Measurement Token */
194
195 /*
196 * Parallel, Enable, Request, and Report bits are 0, Duration is
197 * reserved.
198 */
199 wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
200 wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
201
202 /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
203 /* Location Subject */
204 wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
205
206 /* Optional Subelements */
207 /*
208 * IEEE P802.11-REVmc/D5.0 Figure 9-170
209 * The Maximum Age subelement is required, otherwise the AP can
210 * send only data that was determined after receiving the
211 * request. Setting it here to unlimited age.
212 */
213 wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
214 wpabuf_put_u8(buf, 2);
215 wpabuf_put_le16(buf, 0xffff);
216 }
217
218 if (civic) {
219 /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
220 wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
221 wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
222
223 /*
224 * Measurement token; nonzero number that is unique among the
225 * Measurement Request elements in a particular frame.
226 */
227 wpabuf_put_u8(buf, 2); /* Measurement Token */
228
229 /*
230 * Parallel, Enable, Request, and Report bits are 0, Duration is
231 * reserved.
232 */
233 wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
234 /* Measurement Type */
235 wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
236
237 /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
238 * Location Civic request */
239 /* Location Subject */
240 wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
241 wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
242 /* Location Service Interval Units: Seconds */
243 wpabuf_put_u8(buf, 0);
244 /* Location Service Interval: 0 - Only one report is requested
245 */
246 wpabuf_put_le16(buf, 0);
247 /* No optional subelements */
248 }
249
250 wpa_s->rrm.next_neighbor_rep_token++;
251
252 if (wpa_drv_send_action(wpa_s, 0, 0,
253 wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
254 wpa_dbg(wpa_s, MSG_DEBUG,
255 "RRM: Failed to send Neighbor Report Request");
256 wpabuf_free(buf);
257 return -ECANCELED;
258 }
259
260 wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
261 wpa_s->rrm.notify_neighbor_rep = cb;
262 eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
263 wpas_rrm_neighbor_rep_timeout_handler,
264 &wpa_s->rrm, NULL);
265
266 wpabuf_free(buf);
267 return 0;
268 }
269
270
wpas_rrm_report_elem(struct wpabuf ** buf,u8 token,u8 mode,u8 type,const u8 * data,size_t data_len)271 static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type,
272 const u8 *data, size_t data_len)
273 {
274 if (wpabuf_resize(buf, 5 + data_len))
275 return -1;
276
277 wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT);
278 wpabuf_put_u8(*buf, 3 + data_len);
279 wpabuf_put_u8(*buf, token);
280 wpabuf_put_u8(*buf, mode);
281 wpabuf_put_u8(*buf, type);
282
283 if (data_len)
284 wpabuf_put_data(*buf, data, data_len);
285
286 return 0;
287 }
288
wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant * wpa_s,const u8 * data,size_t len)289 static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s,
290 const u8 *data, size_t len)
291 {
292 struct wpabuf *report = wpabuf_alloc(len + 3);
293
294 if (!report)
295 return;
296
297 wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT);
298 wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
299 wpabuf_put_u8(report, wpa_s->rrm.token);
300
301 wpabuf_put_data(report, data, len);
302
303 if (wpa_drv_send_action(wpa_s, 0, 0,
304 wpabuf_head(report), wpabuf_len(report), 0)) {
305 wpa_printf(MSG_ERROR,
306 "RRM: Radio measurement report failed: Sending Action frame failed");
307 }
308
309 wpabuf_free(report);
310 }
311
312
wpas_rrm_beacon_rep_update_last_frame(u8 * pos,size_t len)313 static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len)
314 {
315 struct rrm_measurement_report_element *msr_rep;
316 u8 *end = pos + len;
317 u8 *msr_rep_end;
318 struct rrm_measurement_beacon_report *rep = NULL;
319 u8 *subelem;
320
321 /* Find the last beacon report element */
322 while (end - pos >= (int) sizeof(*msr_rep)) {
323 msr_rep = (struct rrm_measurement_report_element *) pos;
324 msr_rep_end = pos + msr_rep->len + 2;
325
326 if (msr_rep->eid != WLAN_EID_MEASURE_REPORT ||
327 msr_rep_end > end) {
328 /* Should not happen. This indicates a bug. */
329 wpa_printf(MSG_ERROR,
330 "RRM: non-measurement report element in measurement report frame");
331 return -1;
332 }
333
334 if (msr_rep->type == MEASURE_TYPE_BEACON)
335 rep = (struct rrm_measurement_beacon_report *)
336 msr_rep->variable;
337
338 pos += pos[1] + 2;
339 }
340
341 if (!rep)
342 return 0;
343
344 subelem = rep->variable;
345 while (subelem + 2 < msr_rep_end &&
346 subelem[0] != WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION)
347 subelem += 2 + subelem[1];
348
349 if (subelem + 2 < msr_rep_end &&
350 subelem[0] == WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION &&
351 subelem[1] == 1 &&
352 subelem + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end)
353 subelem[2] = 1;
354
355 return 0;
356 }
357
358
wpas_rrm_send_msr_report(struct wpa_supplicant * wpa_s,struct wpabuf * buf)359 static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
360 struct wpabuf *buf)
361 {
362 int len = wpabuf_len(buf);
363 u8 *pos = wpabuf_mhead_u8(buf), *next = pos;
364
365 #define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
366
367 while (len) {
368 int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
369
370 if (send_len == len)
371 wpas_rrm_beacon_rep_update_last_frame(pos, len);
372
373 if (send_len == len ||
374 (send_len + next[1] + 2) > MPDU_REPORT_LEN) {
375 wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
376 len -= send_len;
377 pos = next;
378 }
379
380 if (len)
381 next += next[1] + 2;
382 }
383 #undef MPDU_REPORT_LEN
384 }
385
wpas_get_op_chan_phy(int channel,const u8 * ies,size_t ies_len,u8 * op_class,u8 * chan,u8 * phy_type)386 static int wpas_get_op_chan_phy(int channel, const u8 *ies, size_t ies_len,
387 u8 *op_class, u8 *chan, u8 *phy_type)
388 {
389 const u8 *ie;
390 int sec_chan = 0;
391 struct ieee80211_ht_operation *ht_oper = NULL;
392
393 ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
394 if (ie && ie[1] >= 2) {
395 ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
396
397 if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
398 sec_chan = 1;
399 else if (ht_oper->ht_param &
400 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
401 sec_chan = -1;
402 }
403
404 *op_class = get_operating_class(channel, sec_chan);
405
406 *phy_type = (sec_chan != 0) ? PHY_TYPE_HT : PHY_TYPE_ERP;
407
408 return 0;
409 }
410
411
wpas_beacon_rep_add_frame_body(struct bitfield * eids,enum beacon_report_detail detail,struct wpa_bss * bss,u8 * buf,size_t buf_len,u8 ** ies_buf,size_t * ie_len,int add_fixed)412 static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
413 enum beacon_report_detail detail,
414 struct wpa_bss *bss, u8 *buf,
415 size_t buf_len, u8 **ies_buf,
416 size_t *ie_len, int add_fixed)
417 {
418 u8 *ies = *ies_buf;
419 size_t ies_len = *ie_len;
420 u8 *pos = buf;
421 int rem_len;
422
423 rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
424 sizeof(struct rrm_measurement_report_element) - 2 -
425 REPORTED_FRAME_BODY_SUBELEM_LEN;
426
427 if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
428 wpa_printf(MSG_DEBUG,
429 "Beacon Request: Invalid reporting detail: %d",
430 detail);
431 return -1;
432 }
433
434 if (detail == BEACON_REPORT_DETAIL_NONE)
435 return 0;
436
437 /*
438 * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
439 * beacon interval(2) + capabilities(2) = 14 bytes
440 */
441 if (add_fixed && buf_len < 14)
442 return -1;
443
444 *pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
445 /* The length will be filled later */
446 pos++;
447
448 if (add_fixed) {
449 WPA_PUT_LE64(pos, bss->tsf);
450 pos += sizeof(bss->tsf);
451 WPA_PUT_LE16(pos, bss->beacon_int);
452 pos += 2;
453 WPA_PUT_LE16(pos, bss->caps);
454 pos += 2;
455 }
456
457 rem_len -= pos - buf;
458
459 /*
460 * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame
461 * body subelement causes the element to exceed the maximum element
462 * size, the subelement is truncated so that the last IE is a complete
463 * IE. So even when required to report all IEs, add elements one after
464 * the other and stop once there is no more room in the measurement
465 * element.
466 */
467 while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
468 if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
469 (eids && bitfield_is_set(eids, ies[0]))) {
470 u8 elen = ies[1];
471
472 if (2 + elen > buf + buf_len - pos ||
473 2 + elen > rem_len)
474 break;
475
476 *pos++ = ies[0];
477 *pos++ = elen;
478 os_memcpy(pos, ies + 2, elen);
479 pos += elen;
480 rem_len -= 2 + elen;
481 }
482
483 ies_len -= 2 + ies[1];
484 ies += 2 + ies[1];
485 }
486
487 *ie_len = ies_len;
488 *ies_buf = ies;
489
490 /* Now the length is known */
491 buf[1] = pos - buf - 2;
492 return pos - buf;
493 }
494
495
wpas_add_beacon_rep_elem(struct beacon_rep_data * data,struct wpa_bss * bss,struct wpabuf ** wpa_buf,struct rrm_measurement_beacon_report * rep,u8 ** ie,size_t * ie_len,u8 idx)496 static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
497 struct wpa_bss *bss,
498 struct wpabuf **wpa_buf,
499 struct rrm_measurement_beacon_report *rep,
500 u8 **ie, size_t *ie_len, u8 idx)
501 {
502 int ret;
503 u8 *buf, *pos;
504 u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN +
505 (data->last_indication ?
506 BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0);
507
508 /* Maximum element length: Beacon Report element + Reported Frame Body
509 * subelement + all IEs of the reported Beacon frame + Reported Frame
510 * Body Fragment ID subelement */
511 buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len);
512 if (!buf)
513 return -1;
514
515 os_memcpy(buf, rep, sizeof(*rep));
516
517 ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
518 bss, buf + sizeof(*rep),
519 14 + *ie_len, ie, ie_len,
520 idx == 0);
521 if (ret < 0)
522 goto out;
523
524 pos = buf + ret + sizeof(*rep);
525 pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID;
526 pos[1] = 2;
527
528 /*
529 * Only one Beacon Report Measurement is supported at a time, so
530 * the Beacon Report ID can always be set to 1.
531 */
532 pos[2] = 1;
533
534 /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7)
535 */
536 pos[3] = idx;
537 if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len)
538 pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS;
539 else
540 pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS;
541
542 pos += REPORTED_FRAME_BODY_SUBELEM_LEN;
543
544 if (data->last_indication) {
545 pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION;
546 pos[1] = 1;
547
548 /* This field will be updated later if this is the last frame */
549 pos[2] = 0;
550 }
551
552 ret = wpas_rrm_report_elem(wpa_buf, data->token,
553 MEASUREMENT_REPORT_MODE_ACCEPT,
554 MEASURE_TYPE_BEACON, buf,
555 ret + sizeof(*rep) + subelems_len);
556 out:
557 os_free(buf);
558 return ret;
559 }
560
561
wpas_add_beacon_rep(struct wpa_supplicant * wpa_s,struct wpabuf ** wpa_buf,struct wpa_bss * bss,u64 start,u64 parent_tsf)562 static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
563 struct wpabuf **wpa_buf, struct wpa_bss *bss,
564 u64 start, u64 parent_tsf)
565 {
566 struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
567 u8 *ies = (u8 *) (bss + 1);
568 u8 *pos = ies;
569 size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
570 struct rrm_measurement_beacon_report rep;
571 u8 idx = 0;
572
573 if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
574 os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
575 return 0;
576
577 if (data->ssid_len &&
578 (data->ssid_len != bss->ssid_len ||
579 os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
580 return 0;
581
582 if (wpas_get_op_chan_phy(bss->channel, ies, ies_len, &rep.op_class,
583 &rep.channel, &rep.report_info) < 0)
584 return 0;
585
586 rep.channel = bss->channel;
587 rep.start_time = host_to_le64(start);
588 rep.duration = host_to_le16(data->scan_params.duration);
589 rep.rcpi = rssi_to_rcpi(bss->level);
590 rep.rsni = 255; /* 255 indicates that RSNI is not available */
591 os_memcpy(rep.bssid, bss->bssid, ETH_ALEN);
592 rep.antenna_id = 0; /* unknown */
593 rep.parent_tsf = host_to_le32(parent_tsf);
594
595 do {
596 int ret;
597
598 ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep,
599 &pos, &ies_len, idx++);
600 if (ret)
601 return ret;
602 } while (data->report_detail != BEACON_REPORT_DETAIL_NONE &&
603 ies_len >= 2);
604
605 return 0;
606 }
607
608
wpas_beacon_rep_no_results(struct wpa_supplicant * wpa_s,struct wpabuf ** buf)609 static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
610 struct wpabuf **buf)
611 {
612 return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
613 MEASUREMENT_REPORT_MODE_ACCEPT,
614 MEASURE_TYPE_BEACON, NULL, 0);
615 }
616
617
wpas_beacon_rep_table(struct wpa_supplicant * wpa_s,struct wpabuf ** buf)618 static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s,
619 struct wpabuf **buf)
620 {
621 size_t i;
622
623 for (i = 0; i < wpa_s->last_scan_res_used; i++) {
624 if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i],
625 0, 0) < 0)
626 break;
627 }
628
629 if (!(*buf))
630 wpas_beacon_rep_no_results(wpa_s, buf);
631
632 wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf);
633 }
634
635
wpas_rrm_refuse_request(struct wpa_supplicant * wpa_s)636 static void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
637 {
638 if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) {
639 struct wpabuf *buf = NULL;
640
641 if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token,
642 MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
643 MEASURE_TYPE_BEACON, NULL, 0)) {
644 wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
645 wpabuf_free(buf);
646 return;
647 }
648
649 wpas_rrm_send_msr_report(wpa_s, buf);
650 wpabuf_free(buf);
651 }
652
653 wpas_clear_beacon_rep_data(wpa_s);
654 }
655
656
wpas_rrm_scan_timeout(void * eloop_ctx,void * timeout_ctx)657 static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
658 {
659 struct wpa_supplicant *wpa_s = eloop_ctx;
660 struct wpa_driver_scan_params *params =
661 &wpa_s->beacon_rep_data.scan_params;
662 u16 prev_duration = params->duration;
663
664 if (!wpa_s->current_bss)
665 return;
666
667 os_get_reltime(&wpa_s->beacon_rep_scan);
668 wpa_s->scan_reason = REASON_RRM_BEACON_REPORT;
669 if (wpa_supplicant_trigger_scan(wpa_s, params) < 0)
670 wpas_rrm_refuse_request(wpa_s);
671 params->duration = prev_duration;
672 }
673
674
wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant * wpa_s,struct beacon_rep_data * data,u8 sid,u8 slen,const u8 * subelem)675 static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s,
676 struct beacon_rep_data *data,
677 u8 sid, u8 slen, const u8 *subelem)
678 {
679 u8 report_info, i;
680
681 switch (sid) {
682 case WLAN_BEACON_REQUEST_SUBELEM_SSID:
683 if (!slen) {
684 wpa_printf(MSG_DEBUG,
685 "SSID subelement with zero length - wildcard SSID");
686 break;
687 }
688
689 if (slen > SSID_MAX_LEN) {
690 wpa_printf(MSG_DEBUG,
691 "Invalid SSID subelement length: %u", slen);
692 return -1;
693 }
694
695 data->ssid_len = slen;
696 os_memcpy(data->ssid, subelem, data->ssid_len);
697 break;
698 case WLAN_BEACON_REQUEST_SUBELEM_INFO:
699 if (slen != 2) {
700 wpa_printf(MSG_DEBUG,
701 "Invalid reporting information subelement length: %u",
702 slen);
703 return -1;
704 }
705
706 report_info = subelem[0];
707 if (report_info != 0) {
708 wpa_printf(MSG_DEBUG,
709 "reporting information=%u is not supported",
710 report_info);
711 return 0;
712 }
713 break;
714 case WLAN_BEACON_REQUEST_SUBELEM_DETAIL:
715 if (slen != 1) {
716 wpa_printf(MSG_DEBUG,
717 "Invalid reporting detail subelement length: %u",
718 slen);
719 return -1;
720 }
721
722 data->report_detail = subelem[0];
723 if (data->report_detail >
724 BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
725 wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u",
726 subelem[0]);
727 return -1;
728 }
729
730 break;
731 case WLAN_BEACON_REQUEST_SUBELEM_REQUEST:
732 if (data->report_detail !=
733 BEACON_REPORT_DETAIL_REQUESTED_ONLY) {
734 wpa_printf(MSG_DEBUG,
735 "Beacon request: request subelement is present but report detail is %u",
736 data->report_detail);
737 return -1;
738 }
739
740 if (!slen) {
741 wpa_printf(MSG_DEBUG,
742 "Invalid request subelement length: %u",
743 slen);
744 return -1;
745 }
746
747 if (data->eids) {
748 wpa_printf(MSG_DEBUG,
749 "Beacon Request: Request subelement appears more than once");
750 return -1;
751 }
752
753 data->eids = bitfield_alloc(255);
754 if (!data->eids) {
755 wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap");
756 return -1;
757 }
758
759 for (i = 0; i < slen; i++)
760 bitfield_set(data->eids, subelem[i]);
761 break;
762 case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
763 /* Skip - it will be processed when freqs are added */
764 break;
765 case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION:
766 if (slen != 1) {
767 wpa_printf(MSG_DEBUG,
768 "Beacon request: Invalid last indication request subelement length: %u",
769 slen);
770 return -1;
771 }
772
773 data->last_indication = subelem[0];
774 break;
775 default:
776 wpa_printf(MSG_DEBUG,
777 "Beacon request: Unknown subelement id %u", sid);
778 break;
779 }
780
781 return 1;
782 }
783
784
785 /**
786 * Returns 0 if the next element can be processed, 1 if some operation was
787 * triggered, and -1 if processing failed (i.e., the element is in invalid
788 * format or an internal error occurred).
789 */
790 static int
wpas_rm_handle_beacon_req(struct wpa_supplicant * wpa_s,u8 elem_token,int duration_mandatory,const struct rrm_measurement_beacon_request * req,size_t len,struct wpabuf ** buf)791 wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
792 u8 elem_token, int duration_mandatory,
793 const struct rrm_measurement_beacon_request *req,
794 size_t len, struct wpabuf **buf)
795 {
796 struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
797 struct wpa_driver_scan_params *params = &data->scan_params;
798 const u8 *subelems;
799 size_t elems_len;
800 u16 rand_interval;
801 u32 interval_usec;
802 u32 _rand;
803 int ret = 0, res;
804 u8 reject_mode;
805
806 if (len < sizeof(*req))
807 return -1;
808
809 if (req->mode != BEACON_REPORT_MODE_PASSIVE &&
810 req->mode != BEACON_REPORT_MODE_ACTIVE &&
811 req->mode != BEACON_REPORT_MODE_TABLE)
812 return 0;
813
814 subelems = req->variable;
815 elems_len = len - sizeof(*req);
816 rand_interval = le_to_host16(req->rand_interval);
817
818 os_memset(data, 0, sizeof(*data));
819
820 data->token = elem_token;
821
822 /* default reporting detail is all fixed length fields and all
823 * elements */
824 data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS;
825 os_memcpy(data->bssid, req->bssid, ETH_ALEN);
826
827 while (elems_len >= 2) {
828 if (subelems[1] > elems_len - 2) {
829 wpa_printf(MSG_DEBUG,
830 "Beacon Request: Truncated subelement");
831 ret = -1;
832 goto out;
833 }
834
835 res = wpas_rm_handle_beacon_req_subelem(
836 wpa_s, data, subelems[0], subelems[1], &subelems[2]);
837 if (res < 0) {
838 ret = res;
839 goto out;
840 } else if (!res) {
841 reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE;
842 goto out_reject;
843 }
844
845 elems_len -= 2 + subelems[1];
846 subelems += 2 + subelems[1];
847 }
848
849 if (req->mode == BEACON_REPORT_MODE_TABLE) {
850 wpas_beacon_rep_table(wpa_s, buf);
851 goto out;
852 }
853 params->channel = req->channel;
854 #ifdef ESP_SUPPLICANT
855 if (params->channel == 0xff) {
856 /* set it to zero */
857 params->channel = 0;
858 }
859 #endif
860 params->duration = le_to_host16(req->duration);
861 params->duration_mandatory = duration_mandatory;
862 params->mode = req->mode;
863 if (!params->duration) {
864 wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
865 ret = -1;
866 goto out;
867 }
868
869 if (data->ssid_len) {
870 params->ssids[params->num_ssids].ssid = data->ssid;
871 params->ssids[params->num_ssids++].ssid_len = data->ssid_len;
872 }
873
874 if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
875 _rand = os_random();
876 interval_usec = (_rand % (rand_interval + 1)) * 1024;
877 os_sleep(0, interval_usec);
878 wpas_rrm_scan_timeout(wpa_s, NULL);
879 return 1;
880 out_reject:
881 if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
882 wpas_rrm_report_elem(buf, elem_token, reject_mode,
883 MEASURE_TYPE_BEACON, NULL, 0) < 0) {
884 wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
885 ret = -1;
886 }
887 out:
888 wpas_clear_beacon_rep_data(wpa_s);
889 return ret;
890 }
891
892
893 static int
wpas_rrm_handle_msr_req_element(struct wpa_supplicant * wpa_s,const struct rrm_measurement_request_element * req,struct wpabuf ** buf)894 wpas_rrm_handle_msr_req_element(
895 struct wpa_supplicant *wpa_s,
896 const struct rrm_measurement_request_element *req,
897 struct wpabuf **buf)
898 {
899 int duration_mandatory;
900
901 wpa_printf(MSG_DEBUG, "Measurement request type %d token %d",
902 req->type, req->token);
903
904 if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) {
905 /* Enable bit is not supported for now */
906 wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore");
907 return 0;
908 }
909
910 if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) &&
911 req->type > MEASURE_TYPE_RPI_HIST) {
912 /* Parallel measurements are not supported for now */
913 wpa_printf(MSG_DEBUG,
914 "RRM: Parallel measurements are not supported, reject");
915 goto reject;
916 }
917
918 duration_mandatory =
919 !!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY);
920
921 switch (req->type) {
922 case MEASURE_TYPE_BEACON:
923 return wpas_rm_handle_beacon_req(wpa_s, req->token,
924 duration_mandatory,
925 (const void *) req->variable,
926 req->len - 3, buf);
927 default:
928 wpa_printf(MSG_INFO,
929 "RRM: Unsupported radio measurement type %u",
930 req->type);
931 break;
932 }
933
934 reject:
935 if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
936 wpas_rrm_report_elem(buf, req->token,
937 MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
938 req->type, NULL, 0) < 0) {
939 wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
940 return -1;
941 }
942
943 return 0;
944 }
945
946
947 static struct wpabuf *
wpas_rrm_process_msr_req_elems(struct wpa_supplicant * wpa_s,const u8 * pos,size_t len)948 wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos,
949 size_t len)
950 {
951 struct wpabuf *buf = NULL;
952
953 while (len) {
954 const struct rrm_measurement_request_element *req;
955 int res;
956
957 if (len < 2) {
958 wpa_printf(MSG_DEBUG, "RRM: Truncated element");
959 goto out;
960 }
961
962 req = (const struct rrm_measurement_request_element *) pos;
963 if (req->eid != WLAN_EID_MEASURE_REQUEST) {
964 wpa_printf(MSG_DEBUG,
965 "RRM: Expected Measurement Request element, but EID is %u",
966 req->eid);
967 printf("len is %d", len);
968 goto out;
969 }
970
971 if (req->len < 3) {
972 wpa_printf(MSG_DEBUG, "RRM: Element length too short");
973 goto out;
974 }
975
976 if (req->len > len - 2) {
977 wpa_printf(MSG_DEBUG, "RRM: Element length too long");
978 goto out;
979 }
980
981 res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf);
982 if (res < 0)
983 goto out;
984
985 pos += req->len + 2;
986 len -= req->len + 2;
987 }
988
989 return buf;
990
991 out:
992 wpabuf_free(buf);
993 return NULL;
994 }
995
996
wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * dst,const u8 * frame,size_t len)997 void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
998 const u8 *src, const u8 *dst,
999 const u8 *frame, size_t len)
1000 {
1001 struct wpabuf *report;
1002
1003 if (!wpa_s->rrm.rrm_used) {
1004 wpa_printf(MSG_INFO,
1005 "RRM: Ignoring radio measurement request: Not RRM network");
1006 return;
1007 }
1008
1009 if (len < 3) {
1010 wpa_printf(MSG_INFO,
1011 "RRM: Ignoring too short radio measurement request");
1012 return;
1013 }
1014
1015 wpa_s->rrm.token = *frame;
1016 os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN);
1017
1018 /* Number of repetitions is not supported */
1019
1020 report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3);
1021 if (!report)
1022 return;
1023
1024 wpas_rrm_send_msr_report(wpa_s, report);
1025 wpabuf_free(report);
1026 }
1027
1028
wpas_rrm_handle_link_measurement_request(struct wpa_supplicant * wpa_s,const u8 * src,const u8 * frame,size_t len,int rssi)1029 void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
1030 const u8 *src,
1031 const u8 *frame, size_t len,
1032 int rssi)
1033 {
1034 struct wpabuf *buf;
1035 const struct rrm_link_measurement_request *req;
1036 struct rrm_link_measurement_report report;
1037
1038 req = (const struct rrm_link_measurement_request *) frame;
1039 if (len < sizeof(*req)) {
1040 wpa_printf(MSG_INFO,
1041 "RRM: Link measurement report failed. Request too short");
1042 return;
1043 }
1044
1045 os_memset(&report, 0, sizeof(report));
1046 report.dialog_token = req->dialog_token;
1047 report.tpc.eid = WLAN_EID_TPC_REPORT;
1048 report.tpc.len = 2;
1049 /* Note: The driver is expected to update report.tpc.tx_power and
1050 * report.tpc.link_margin subfields when sending out this frame.
1051 * Similarly, the driver would need to update report.rx_ant_id and
1052 * report.tx_ant_id subfields. */
1053
1054 #ifdef ESP_SUPPLICANT
1055 esp_get_tx_power(&report.tpc.tx_power);
1056 /* Minimum RSSI = -96 dbm */
1057 report.tpc.link_margin = rssi + 96;
1058 #endif
1059 report.rsni = 255; /* 255 indicates that RSNI is not available */
1060 report.rcpi = rssi_to_rcpi(rssi);
1061
1062 /* action_category + action_code */
1063 buf = wpabuf_alloc(2 + sizeof(report));
1064 if (buf == NULL) {
1065 wpa_printf(MSG_ERROR,
1066 "RRM: Link measurement report failed. Buffer allocation failed");
1067 return;
1068 }
1069
1070 wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
1071 wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
1072 wpabuf_put_data(buf, &report, sizeof(report));
1073 wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf);
1074
1075 if (wpa_drv_send_action(wpa_s, 0, 0,
1076 wpabuf_head(buf), wpabuf_len(buf), 0)) {
1077 wpa_printf(MSG_ERROR,
1078 "RRM: Link measurement report failed. Send action failed");
1079 }
1080 wpabuf_free(buf);
1081 }
1082
1083
wpas_beacon_rep_scan_process(struct wpa_supplicant * wpa_s,u64 scan_start_tsf)1084 int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
1085 u64 scan_start_tsf)
1086 {
1087 size_t i = 0;
1088 struct wpabuf *buf = NULL;
1089 struct wpa_bss *bss = NULL;
1090
1091 if (!wpa_s->beacon_rep_data.token)
1092 return 0;
1093
1094 if (!wpa_s->current_bss)
1095 goto out;
1096
1097 wpa_printf(MSG_DEBUG, "RRM: TSF current BSS: " MACSTR,
1098 MAC2STR(wpa_s->current_bss->bssid));
1099
1100 for (i = 0; i < wpa_s->num_bss; i++) {
1101 bss = wpa_bss_get_next_bss(wpa_s, bss);
1102
1103 if (!bss)
1104 continue;
1105
1106 if (wpa_s->beacon_rep_data.scan_params.channel &&
1107 bss->channel != wpa_s->beacon_rep_data.scan_params.channel)
1108 continue;
1109 /* We flush scan results before issuing scan again */
1110 #ifndef ESP_SUPPLICANT
1111 /*
1112 * Don't report results that were not received during the
1113 * current measurement.
1114 */
1115 if (scan_start_tsf <
1116 scan_res->res[i]->parent_tsf) {
1117 struct os_reltime update_time, diff;
1118
1119 /* For now, allow 7 ms older results due to some
1120 * unknown issue with cfg80211 BSS table updates during
1121 * a scan with the current BSS.
1122 * TODO: Fix this more properly to avoid having to have
1123 * this type of hacks in place. */
1124 calculate_update_time(&scan_res->fetch_time,
1125 scan_res->res[i]->age,
1126 &update_time);
1127 os_reltime_sub(&wpa_s->beacon_rep_scan,
1128 &update_time, &diff);
1129 if (os_reltime_before(&update_time,
1130 &wpa_s->beacon_rep_scan) &&
1131 (diff.sec || diff.usec >= 8000)) {
1132 wpa_printf(MSG_ERROR,
1133 "RRM: Ignore scan result for " MACSTR
1134 " due to old update (age(ms) %u, calculated age %u.%06u seconds)",
1135 MAC2STR(scan_res->res[i]->bssid),
1136 scan_res->res[i]->age,
1137 (unsigned int) diff.sec,
1138 (unsigned int) diff.usec);
1139 continue;
1140 }
1141 } else {
1142 continue;
1143 }
1144 #endif
1145 if (wpas_add_beacon_rep(wpa_s, &buf, bss, scan_start_tsf,
1146 bss->parent_tsf) < 0)
1147 break;
1148 }
1149
1150 if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf))
1151 goto out;
1152
1153 wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf);
1154
1155 wpas_rrm_send_msr_report(wpa_s, buf);
1156 wpabuf_free(buf);
1157
1158 out:
1159 wpas_clear_beacon_rep_data(wpa_s);
1160 return 1;
1161 }
1162
1163
wpas_clear_beacon_rep_data(struct wpa_supplicant * wpa_s)1164 void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s)
1165 {
1166 struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
1167
1168 eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL);
1169 bitfield_free(data->eids);
1170 os_memset(data, 0, sizeof(*data));
1171 }
1172