vendor/wpa_supplicant: upgrade from 2.1 to 2.9
[dragonfly.git] / contrib / wpa_supplicant / src / ap / rrm.c
1 /*
2  * hostapd / Radio Measurement (RRM)
3  * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
4  * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
5  * Copyright (c) 2016-2017, Jouni Malinen <j@w1.fi>
6  *
7  * This software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10
11 #include "utils/includes.h"
12
13 #include "utils/common.h"
14 #include "common/wpa_ctrl.h"
15 #include "hostapd.h"
16 #include "ap_drv_ops.h"
17 #include "sta_info.h"
18 #include "eloop.h"
19 #include "neighbor_db.h"
20 #include "rrm.h"
21
22 #define HOSTAPD_RRM_REQUEST_TIMEOUT 5
23
24
25 static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
26 {
27         struct hostapd_data *hapd = eloop_data;
28
29         wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
30                    hapd->lci_req_token);
31         hapd->lci_req_active = 0;
32 }
33
34
35 static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
36                                       const u8 *pos, size_t len)
37 {
38         if (!hapd->lci_req_active || hapd->lci_req_token != token) {
39                 wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
40                 return;
41         }
42
43         hapd->lci_req_active = 0;
44         eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
45         wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
46 }
47
48
49 static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
50 {
51         struct hostapd_data *hapd = eloop_data;
52
53         wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
54                    hapd->range_req_token);
55         hapd->range_req_active = 0;
56 }
57
58
59 static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
60                                         const u8 *pos, size_t len)
61 {
62         if (!hapd->range_req_active || hapd->range_req_token != token) {
63                 wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
64                            token);
65                 return;
66         }
67
68         hapd->range_req_active = 0;
69         eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
70         wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
71 }
72
73
74 static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
75                                          const u8 *addr, u8 token, u8 rep_mode,
76                                          const u8 *pos, size_t len)
77 {
78         char report[2 * 255 + 1];
79
80         wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR,
81                    token, len, MAC2STR(addr));
82         /* Skip to the beginning of the Beacon report */
83         if (len < 3)
84                 return;
85         pos += 3;
86         len -= 3;
87         report[0] = '\0';
88         if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0)
89                 return;
90         wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
91                 MAC2STR(addr), token, rep_mode, report);
92 }
93
94
95 static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
96                                              const u8 *buf, size_t len)
97 {
98         const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
99         const u8 *pos, *ie, *end;
100         u8 token, rep_mode;
101
102         end = buf + len;
103         token = mgmt->u.action.u.rrm.dialog_token;
104         pos = mgmt->u.action.u.rrm.variable;
105
106         while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
107                 if (ie[1] < 3) {
108                         wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
109                         break;
110                 }
111
112                 rep_mode = ie[3];
113                 wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u",
114                            rep_mode, ie[4]);
115
116                 switch (ie[4]) {
117                 case MEASURE_TYPE_LCI:
118                         hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
119                         break;
120                 case MEASURE_TYPE_FTM_RANGE:
121                         hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
122                         break;
123                 case MEASURE_TYPE_BEACON:
124                         hostapd_handle_beacon_report(hapd, mgmt->sa, token,
125                                                      rep_mode, ie + 2, ie[1]);
126                         break;
127                 default:
128                         wpa_printf(MSG_DEBUG,
129                                    "Measurement report type %u is not supported",
130                                    ie[4]);
131                         break;
132                 }
133
134                 pos = ie + ie[1] + 2;
135         }
136 }
137
138
139 static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
140 {
141         const u8 *subelem;
142
143         /* Range Request element + Location Subject + Maximum Age subelement */
144         if (len < 3 + 1 + 4)
145                 return 0;
146
147         /* Subelements are arranged as IEs */
148         subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
149         if (subelem && subelem[1] == 2)
150                 return WPA_GET_LE16(subelem + 2);
151
152         return 0;
153 }
154
155
156 static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
157 {
158         struct os_time curr, diff;
159         unsigned long diff_l;
160
161         if (nr->stationary || max_age == 0xffff)
162                 return 1;
163
164         if (!max_age)
165                 return 0;
166
167         if (os_get_time(&curr))
168                 return 0;
169
170         os_time_sub(&curr, &nr->lci_date, &diff);
171
172         /* avoid overflow */
173         if (diff.sec > 0xffff)
174                 return 0;
175
176         /* LCI age is calculated in 10th of a second units. */
177         diff_l = diff.sec * 10 + diff.usec / 100000;
178
179         return max_age > diff_l;
180 }
181
182
183 static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
184                                           struct hostapd_neighbor_entry *nr,
185                                           int send_lci, int send_civic)
186 {
187         size_t len = 2 + wpabuf_len(nr->nr);
188
189         if (send_lci && nr->lci)
190                 len += 2 + wpabuf_len(nr->lci);
191
192         if (send_civic && nr->civic)
193                 len += 2 + wpabuf_len(nr->civic);
194
195         return len;
196 }
197
198
199 static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
200                                          const u8 *addr, u8 dialog_token,
201                                          struct wpa_ssid_value *ssid, u8 lci,
202                                          u8 civic, u16 lci_max_age)
203 {
204         struct hostapd_neighbor_entry *nr;
205         struct wpabuf *buf;
206         u8 *msmt_token;
207
208         /*
209          * The number and length of the Neighbor Report elements in a Neighbor
210          * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
211          * of RRM header.
212          */
213         buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
214         if (!buf)
215                 return;
216
217         wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
218         wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
219         wpabuf_put_u8(buf, dialog_token);
220
221         dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
222                          list) {
223                 int send_lci;
224                 size_t len;
225
226                 if (ssid->ssid_len != nr->ssid.ssid_len ||
227                     os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
228                         continue;
229
230                 send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
231                 len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
232
233                 if (len - 2 > 0xff) {
234                         wpa_printf(MSG_DEBUG,
235                                    "NR entry for " MACSTR " exceeds 0xFF bytes",
236                                    MAC2STR(nr->bssid));
237                         continue;
238                 }
239
240                 if (len > wpabuf_tailroom(buf))
241                         break;
242
243                 wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
244                 wpabuf_put_u8(buf, len - 2);
245                 wpabuf_put_buf(buf, nr->nr);
246
247                 if (send_lci && nr->lci) {
248                         wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
249                         wpabuf_put_u8(buf, wpabuf_len(nr->lci));
250                         /*
251                          * Override measurement token - the first byte of the
252                          * Measurement Report element.
253                          */
254                         msmt_token = wpabuf_put(buf, 0);
255                         wpabuf_put_buf(buf, nr->lci);
256                         *msmt_token = lci;
257                 }
258
259                 if (civic && nr->civic) {
260                         wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
261                         wpabuf_put_u8(buf, wpabuf_len(nr->civic));
262                         /*
263                          * Override measurement token - the first byte of the
264                          * Measurement Report element.
265                          */
266                         msmt_token = wpabuf_put(buf, 0);
267                         wpabuf_put_buf(buf, nr->civic);
268                         *msmt_token = civic;
269                 }
270         }
271
272         hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
273                                 wpabuf_head(buf), wpabuf_len(buf));
274         wpabuf_free(buf);
275 }
276
277
278 static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
279                                           const u8 *buf, size_t len)
280 {
281         const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
282         const u8 *pos, *ie, *end;
283         struct wpa_ssid_value ssid = {
284                 .ssid_len = 0
285         };
286         u8 token;
287         u8 lci = 0, civic = 0; /* Measurement tokens */
288         u16 lci_max_age = 0;
289
290         if (!(hapd->conf->radio_measurements[0] &
291               WLAN_RRM_CAPS_NEIGHBOR_REPORT))
292                 return;
293
294         end = buf + len;
295
296         token = mgmt->u.action.u.rrm.dialog_token;
297         pos = mgmt->u.action.u.rrm.variable;
298         len = end - pos;
299
300         ie = get_ie(pos, len, WLAN_EID_SSID);
301         if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
302                 ssid.ssid_len = ie[1];
303                 os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
304         } else {
305                 ssid.ssid_len = hapd->conf->ssid.ssid_len;
306                 os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
307         }
308
309         while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
310                 if (ie[1] < 3)
311                         break;
312
313                 wpa_printf(MSG_DEBUG,
314                            "Neighbor report request, measure type %u",
315                            ie[4]);
316
317                 switch (ie[4]) { /* Measurement Type */
318                 case MEASURE_TYPE_LCI:
319                         lci = ie[2]; /* Measurement Token */
320                         lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
321                                                                          ie[1]);
322                         break;
323                 case MEASURE_TYPE_LOCATION_CIVIC:
324                         civic = ie[2]; /* Measurement token */
325                         break;
326                 }
327
328                 pos = ie + ie[1] + 2;
329                 len = end - pos;
330         }
331
332         hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
333                                      lci_max_age);
334 }
335
336
337 void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
338                                       const u8 *buf, size_t len)
339 {
340         const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
341
342         /*
343          * Check for enough bytes: header + (1B)Category + (1B)Action +
344          * (1B)Dialog Token.
345          */
346         if (len < IEEE80211_HDRLEN + 3)
347                 return;
348
349         wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
350                    mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
351
352         switch (mgmt->u.action.u.rrm.action) {
353         case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
354                 hostapd_handle_radio_msmt_report(hapd, buf, len);
355                 break;
356         case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
357                 hostapd_handle_nei_report_req(hapd, buf, len);
358                 break;
359         default:
360                 wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
361                            mgmt->u.action.u.rrm.action);
362                 break;
363         }
364 }
365
366
367 int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
368 {
369         struct wpabuf *buf;
370         struct sta_info *sta = ap_get_sta(hapd, addr);
371         int ret;
372
373         if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
374                 wpa_printf(MSG_INFO,
375                            "Request LCI: Destination address is not connected");
376                 return -1;
377         }
378
379         if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
380                 wpa_printf(MSG_INFO,
381                            "Request LCI: Station does not support LCI in RRM");
382                 return -1;
383         }
384
385         if (hapd->lci_req_active) {
386                 wpa_printf(MSG_DEBUG,
387                            "Request LCI: LCI request is already in process, overriding");
388                 hapd->lci_req_active = 0;
389                 eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
390                                      NULL);
391         }
392
393         /* Measurement request (5) + Measurement element with LCI (10) */
394         buf = wpabuf_alloc(5 + 10);
395         if (!buf)
396                 return -1;
397
398         hapd->lci_req_token++;
399         /* For wraparounds - the token must be nonzero */
400         if (!hapd->lci_req_token)
401                 hapd->lci_req_token++;
402
403         wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
404         wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
405         wpabuf_put_u8(buf, hapd->lci_req_token);
406         wpabuf_put_le16(buf, 0); /* Number of repetitions */
407
408         wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
409         wpabuf_put_u8(buf, 3 + 1 + 4);
410
411         wpabuf_put_u8(buf, 1); /* Measurement Token */
412         /*
413          * Parallel and Enable bits are 0, Duration, Request, and Report are
414          * reserved.
415          */
416         wpabuf_put_u8(buf, 0);
417         wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
418
419         wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
420
421         wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
422         wpabuf_put_u8(buf, 2);
423         wpabuf_put_le16(buf, 0xffff);
424
425         ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
426                                       wpabuf_head(buf), wpabuf_len(buf));
427         wpabuf_free(buf);
428         if (ret)
429                 return ret;
430
431         hapd->lci_req_active = 1;
432
433         eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
434                                hostapd_lci_rep_timeout_handler, hapd, NULL);
435
436         return 0;
437 }
438
439
440 int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
441                            u16 random_interval, u8 min_ap,
442                            const u8 *responders, unsigned int n_responders)
443 {
444         struct wpabuf *buf;
445         struct sta_info *sta;
446         u8 *len;
447         unsigned int i;
448         int ret;
449
450         wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
451                    " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
452                    random_interval, min_ap, n_responders);
453
454         if (min_ap == 0 || min_ap > n_responders) {
455                 wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
456                 return -1;
457         }
458
459         sta = ap_get_sta(hapd, addr);
460         if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
461                 wpa_printf(MSG_INFO,
462                            "Request range: Destination address is not connected");
463                 return -1;
464         }
465
466         if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
467                 wpa_printf(MSG_ERROR,
468                            "Request range: Destination station does not support FTM range report in RRM");
469                 return -1;
470         }
471
472         if (hapd->range_req_active) {
473                 wpa_printf(MSG_DEBUG,
474                            "Request range: Range request is already in process; overriding");
475                 hapd->range_req_active = 0;
476                 eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
477                                      NULL);
478         }
479
480         /* Action + measurement type + token + reps + EID + len = 7 */
481         buf = wpabuf_alloc(7 + 255);
482         if (!buf)
483                 return -1;
484
485         hapd->range_req_token++;
486         if (!hapd->range_req_token) /* For wraparounds */
487                 hapd->range_req_token++;
488
489         /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
490         wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
491         wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
492         wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
493         wpabuf_put_le16(buf, 0); /* Number of Repetitions */
494
495         /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
496         wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
497         len = wpabuf_put(buf, 1); /* Length will be set later */
498
499         wpabuf_put_u8(buf, 1); /* Measurement Token */
500         /*
501          * Parallel and Enable bits are 0; Duration, Request, and Report are
502          * reserved.
503          */
504         wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
505         wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
506
507         /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
508         wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
509         wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
510
511         /* FTM Range Subelements */
512
513         /*
514          * Taking the neighbor report part of the range request from neighbor
515          * database instead of requesting the separate bits of data from the
516          * user.
517          */
518         for (i = 0; i < n_responders; i++) {
519                 struct hostapd_neighbor_entry *nr;
520
521                 nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
522                                           NULL);
523                 if (!nr) {
524                         wpa_printf(MSG_INFO, "Missing neighbor report for "
525                                    MACSTR, MAC2STR(responders + ETH_ALEN * i));
526                         wpabuf_free(buf);
527                         return -1;
528                 }
529
530                 if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
531                         wpa_printf(MSG_ERROR, "Too long range request");
532                         wpabuf_free(buf);
533                         return -1;
534                 }
535
536                 wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
537                 wpabuf_put_u8(buf, wpabuf_len(nr->nr));
538                 wpabuf_put_buf(buf, nr->nr);
539         }
540
541         /* Action + measurement type + token + reps + EID + len = 7 */
542         *len = wpabuf_len(buf) - 7;
543
544         ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
545                                       wpabuf_head(buf), wpabuf_len(buf));
546         wpabuf_free(buf);
547         if (ret)
548                 return ret;
549
550         hapd->range_req_active = 1;
551
552         eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
553                                hostapd_range_rep_timeout_handler, hapd, NULL);
554
555         return 0;
556 }
557
558
559 void hostapd_clean_rrm(struct hostapd_data *hapd)
560 {
561         hostapd_free_neighbor_db(hapd);
562         eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
563         hapd->lci_req_active = 0;
564         eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
565         hapd->range_req_active = 0;
566 }
567
568
569 int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
570                             u8 req_mode, const struct wpabuf *req)
571 {
572         struct wpabuf *buf;
573         struct sta_info *sta = ap_get_sta(hapd, addr);
574         int ret;
575         enum beacon_report_mode mode;
576         const u8 *pos;
577
578         /* Request data:
579          * Operating Class (1), Channel Number (1), Randomization Interval (2),
580          * Measurement Duration (2), Measurement Mode (1), BSSID (6),
581          * Optional Subelements (variable)
582          */
583         if (wpabuf_len(req) < 13) {
584                 wpa_printf(MSG_INFO, "Beacon request: Too short request data");
585                 return -1;
586         }
587         pos = wpabuf_head(req);
588         mode = pos[6];
589
590         if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
591                 wpa_printf(MSG_INFO,
592                            "Beacon request: " MACSTR " is not connected",
593                            MAC2STR(addr));
594                 return -1;
595         }
596
597         switch (mode) {
598         case BEACON_REPORT_MODE_PASSIVE:
599                 if (!(sta->rrm_enabled_capa[0] &
600                       WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
601                         wpa_printf(MSG_INFO,
602                                    "Beacon request: " MACSTR
603                                    " does not support passive beacon report",
604                                    MAC2STR(addr));
605                         return -1;
606                 }
607                 break;
608         case BEACON_REPORT_MODE_ACTIVE:
609                 if (!(sta->rrm_enabled_capa[0] &
610                       WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
611                         wpa_printf(MSG_INFO,
612                                    "Beacon request: " MACSTR
613                                    " does not support active beacon report",
614                                    MAC2STR(addr));
615                         return -1;
616                 }
617                 break;
618         case BEACON_REPORT_MODE_TABLE:
619                 if (!(sta->rrm_enabled_capa[0] &
620                       WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
621                         wpa_printf(MSG_INFO,
622                                    "Beacon request: " MACSTR
623                                    " does not support table beacon report",
624                                    MAC2STR(addr));
625                         return -1;
626                 }
627                 break;
628         default:
629                 wpa_printf(MSG_INFO,
630                            "Beacon request: Unknown measurement mode %d", mode);
631                 return -1;
632         }
633
634         buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
635         if (!buf)
636                 return -1;
637
638         hapd->beacon_req_token++;
639         if (!hapd->beacon_req_token)
640                 hapd->beacon_req_token++;
641
642         wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
643         wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
644         wpabuf_put_u8(buf, hapd->beacon_req_token);
645         wpabuf_put_le16(buf, 0); /* Number of repetitions */
646
647         /* Measurement Request element */
648         wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
649         wpabuf_put_u8(buf, 3 + wpabuf_len(req));
650         wpabuf_put_u8(buf, 1); /* Measurement Token */
651         wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
652         wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
653         wpabuf_put_buf(buf, req);
654
655         ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
656                                       wpabuf_head(buf), wpabuf_len(buf));
657         wpabuf_free(buf);
658         if (ret < 0)
659                 return ret;
660
661         return hapd->beacon_req_token;
662 }
663
664
665 void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
666                                       const struct ieee80211_mgmt *mgmt,
667                                       size_t len, int ok)
668 {
669         if (len < 24 + 3)
670                 return;
671         wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
672                 " %u ack=%d", MAC2STR(mgmt->da),
673                 mgmt->u.action.u.rrm.dialog_token, ok);
674 }