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 
hostapd_lci_rep_timeout_handler(void * eloop_data,void * user_ctx)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 
hostapd_handle_lci_report(struct hostapd_data * hapd,u8 token,const u8 * pos,size_t len)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 
hostapd_range_rep_timeout_handler(void * eloop_data,void * user_ctx)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 
hostapd_handle_range_report(struct hostapd_data * hapd,u8 token,const u8 * pos,size_t len)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 
hostapd_handle_beacon_report(struct hostapd_data * hapd,const u8 * addr,u8 token,u8 rep_mode,const u8 * pos,size_t len)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 
hostapd_handle_radio_msmt_report(struct hostapd_data * hapd,const u8 * buf,size_t len)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 
hostapd_parse_location_lci_req_age(const u8 * buf,size_t len)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 
hostapd_check_lci_age(struct hostapd_neighbor_entry * nr,u16 max_age)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 
hostapd_neighbor_report_len(struct wpabuf * buf,struct hostapd_neighbor_entry * nr,int send_lci,int send_civic)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 
hostapd_send_nei_report_resp(struct hostapd_data * hapd,const u8 * addr,u8 dialog_token,struct wpa_ssid_value * ssid,u8 lci,u8 civic,u16 lci_max_age)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 
hostapd_handle_nei_report_req(struct hostapd_data * hapd,const u8 * buf,size_t len)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 
hostapd_link_mesr_rep_timeout_handler(void * eloop_data,void * user_ctx)337 static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data,
338                                                               void *user_ctx)
339 {
340           struct hostapd_data *hapd = eloop_data;
341 
342           wpa_printf(MSG_DEBUG,
343                        "RRM: Link measurement request (token %u) timed out",
344                        hapd->link_measurement_req_token);
345           hapd->link_mesr_req_active = 0;
346 }
347 
348 
hostapd_handle_link_mesr_report(struct hostapd_data * hapd,const u8 * buf,size_t len)349 static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd,
350                                                       const u8 *buf, size_t len)
351 {
352           const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
353           const struct rrm_link_measurement_report *report;
354           const u8 *pos, *end;
355           char report_msg[2 * 8 + 1];
356 
357           end = buf + len;
358           pos = mgmt->u.action.u.rrm.variable;
359           report = (const struct rrm_link_measurement_report *) (pos - 1);
360           if (end - (const u8 *) report < (int) sizeof(*report))
361                     return;
362 
363           if (!hapd->link_mesr_req_active ||
364               (hapd->link_measurement_req_token != report->dialog_token)) {
365                     wpa_printf(MSG_INFO,
366                                  "Unexpected Link measurement report, token %u",
367                                  report->dialog_token);
368                     return;
369           }
370 
371           hapd->link_mesr_req_active = 0;
372           eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
373 
374           report_msg[0] = '\0';
375           if (wpa_snprintf_hex(report_msg, sizeof(report_msg),
376                                    pos, end - pos) < 0)
377                     return;
378 
379           wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s",
380                     MAC2STR(mgmt->sa), report->dialog_token, report_msg);
381 }
382 
383 
hostapd_handle_radio_measurement(struct hostapd_data * hapd,const u8 * buf,size_t len)384 void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
385                                               const u8 *buf, size_t len)
386 {
387           const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
388 
389           /*
390            * Check for enough bytes: header + (1B)Category + (1B)Action +
391            * (1B)Dialog Token.
392            */
393           if (len < IEEE80211_HDRLEN + 3)
394                     return;
395 
396           wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
397                        mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
398 
399           switch (mgmt->u.action.u.rrm.action) {
400           case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
401                     hostapd_handle_radio_msmt_report(hapd, buf, len);
402                     break;
403           case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
404                     hostapd_handle_nei_report_req(hapd, buf, len);
405                     break;
406           case WLAN_RRM_LINK_MEASUREMENT_REPORT:
407                     hostapd_handle_link_mesr_report(hapd, buf, len);
408                     break;
409           default:
410                     wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
411                                  mgmt->u.action.u.rrm.action);
412                     break;
413           }
414 }
415 
416 
hostapd_send_lci_req(struct hostapd_data * hapd,const u8 * addr)417 int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
418 {
419           struct wpabuf *buf;
420           struct sta_info *sta = ap_get_sta(hapd, addr);
421           int ret;
422 
423           if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
424                     wpa_printf(MSG_INFO,
425                                  "Request LCI: Destination address is not connected");
426                     return -1;
427           }
428 
429           if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
430                     wpa_printf(MSG_INFO,
431                                  "Request LCI: Station does not support LCI in RRM");
432                     return -1;
433           }
434 
435           if (hapd->lci_req_active) {
436                     wpa_printf(MSG_DEBUG,
437                                  "Request LCI: LCI request is already in process, overriding");
438                     hapd->lci_req_active = 0;
439                     eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
440                                              NULL);
441           }
442 
443           /* Measurement request (5) + Measurement element with LCI (10) */
444           buf = wpabuf_alloc(5 + 10);
445           if (!buf)
446                     return -1;
447 
448           hapd->lci_req_token++;
449           /* For wraparounds - the token must be nonzero */
450           if (!hapd->lci_req_token)
451                     hapd->lci_req_token++;
452 
453           wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
454           wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
455           wpabuf_put_u8(buf, hapd->lci_req_token);
456           wpabuf_put_le16(buf, 0); /* Number of repetitions */
457 
458           wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
459           wpabuf_put_u8(buf, 3 + 1 + 4);
460 
461           wpabuf_put_u8(buf, 1); /* Measurement Token */
462           /*
463            * Parallel and Enable bits are 0, Duration, Request, and Report are
464            * reserved.
465            */
466           wpabuf_put_u8(buf, 0);
467           wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
468 
469           wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
470 
471           wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
472           wpabuf_put_u8(buf, 2);
473           wpabuf_put_le16(buf, 0xffff);
474 
475           ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
476                                               wpabuf_head(buf), wpabuf_len(buf));
477           wpabuf_free(buf);
478           if (ret)
479                     return ret;
480 
481           hapd->lci_req_active = 1;
482 
483           eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
484                                      hostapd_lci_rep_timeout_handler, hapd, NULL);
485 
486           return 0;
487 }
488 
489 
hostapd_send_range_req(struct hostapd_data * hapd,const u8 * addr,u16 random_interval,u8 min_ap,const u8 * responders,unsigned int n_responders)490 int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
491                                  u16 random_interval, u8 min_ap,
492                                  const u8 *responders, unsigned int n_responders)
493 {
494           struct wpabuf *buf;
495           struct sta_info *sta;
496           u8 *len;
497           unsigned int i;
498           int ret;
499 
500           wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
501                        " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
502                        random_interval, min_ap, n_responders);
503 
504           if (min_ap == 0 || min_ap > n_responders) {
505                     wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
506                     return -1;
507           }
508 
509           sta = ap_get_sta(hapd, addr);
510           if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
511                     wpa_printf(MSG_INFO,
512                                  "Request range: Destination address is not connected");
513                     return -1;
514           }
515 
516           if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
517                     wpa_printf(MSG_ERROR,
518                                  "Request range: Destination station does not support FTM range report in RRM");
519                     return -1;
520           }
521 
522           if (hapd->range_req_active) {
523                     wpa_printf(MSG_DEBUG,
524                                  "Request range: Range request is already in process; overriding");
525                     hapd->range_req_active = 0;
526                     eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
527                                              NULL);
528           }
529 
530           /* Action + measurement type + token + reps + EID + len = 7 */
531           buf = wpabuf_alloc(7 + 255);
532           if (!buf)
533                     return -1;
534 
535           hapd->range_req_token++;
536           if (!hapd->range_req_token) /* For wraparounds */
537                     hapd->range_req_token++;
538 
539           /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
540           wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
541           wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
542           wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
543           wpabuf_put_le16(buf, 0); /* Number of Repetitions */
544 
545           /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
546           wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
547           len = wpabuf_put(buf, 1); /* Length will be set later */
548 
549           wpabuf_put_u8(buf, 1); /* Measurement Token */
550           /*
551            * Parallel and Enable bits are 0; Duration, Request, and Report are
552            * reserved.
553            */
554           wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
555           wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
556 
557           /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
558           wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
559           wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
560 
561           /* FTM Range Subelements */
562 
563           /*
564            * Taking the neighbor report part of the range request from neighbor
565            * database instead of requesting the separate bits of data from the
566            * user.
567            */
568           for (i = 0; i < n_responders; i++) {
569                     struct hostapd_neighbor_entry *nr;
570 
571                     nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
572                                                     NULL);
573                     if (!nr) {
574                               wpa_printf(MSG_INFO, "Missing neighbor report for "
575                                            MACSTR, MAC2STR(responders + ETH_ALEN * i));
576                               wpabuf_free(buf);
577                               return -1;
578                     }
579 
580                     if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
581                               wpa_printf(MSG_ERROR, "Too long range request");
582                               wpabuf_free(buf);
583                               return -1;
584                     }
585 
586                     wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
587                     wpabuf_put_u8(buf, wpabuf_len(nr->nr));
588                     wpabuf_put_buf(buf, nr->nr);
589           }
590 
591           /* Action + measurement type + token + reps + EID + len = 7 */
592           *len = wpabuf_len(buf) - 7;
593 
594           ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
595                                               wpabuf_head(buf), wpabuf_len(buf));
596           wpabuf_free(buf);
597           if (ret)
598                     return ret;
599 
600           hapd->range_req_active = 1;
601 
602           eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
603                                      hostapd_range_rep_timeout_handler, hapd, NULL);
604 
605           return 0;
606 }
607 
608 
hostapd_clean_rrm(struct hostapd_data * hapd)609 void hostapd_clean_rrm(struct hostapd_data *hapd)
610 {
611           hostapd_free_neighbor_db(hapd);
612           eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
613           hapd->lci_req_active = 0;
614           eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
615           hapd->range_req_active = 0;
616           eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
617 }
618 
619 
hostapd_send_beacon_req(struct hostapd_data * hapd,const u8 * addr,u8 req_mode,const struct wpabuf * req)620 int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
621                                   u8 req_mode, const struct wpabuf *req)
622 {
623           struct wpabuf *buf;
624           struct sta_info *sta = ap_get_sta(hapd, addr);
625           int ret;
626           enum beacon_report_mode mode;
627           const u8 *pos;
628 
629           /* Request data:
630            * Operating Class (1), Channel Number (1), Randomization Interval (2),
631            * Measurement Duration (2), Measurement Mode (1), BSSID (6),
632            * Optional Subelements (variable)
633            */
634           if (wpabuf_len(req) < 13) {
635                     wpa_printf(MSG_INFO, "Beacon request: Too short request data");
636                     return -1;
637           }
638           pos = wpabuf_head(req);
639           mode = pos[6];
640 
641           if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
642                     wpa_printf(MSG_INFO,
643                                  "Beacon request: " MACSTR " is not connected",
644                                  MAC2STR(addr));
645                     return -1;
646           }
647 
648           switch (mode) {
649           case BEACON_REPORT_MODE_PASSIVE:
650                     if (!(sta->rrm_enabled_capa[0] &
651                           WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
652                               wpa_printf(MSG_INFO,
653                                            "Beacon request: " MACSTR
654                                            " does not support passive beacon report",
655                                            MAC2STR(addr));
656                               return -1;
657                     }
658                     break;
659           case BEACON_REPORT_MODE_ACTIVE:
660                     if (!(sta->rrm_enabled_capa[0] &
661                           WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
662                               wpa_printf(MSG_INFO,
663                                            "Beacon request: " MACSTR
664                                            " does not support active beacon report",
665                                            MAC2STR(addr));
666                               return -1;
667                     }
668                     break;
669           case BEACON_REPORT_MODE_TABLE:
670                     if (!(sta->rrm_enabled_capa[0] &
671                           WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
672                               wpa_printf(MSG_INFO,
673                                            "Beacon request: " MACSTR
674                                            " does not support table beacon report",
675                                            MAC2STR(addr));
676                               return -1;
677                     }
678                     break;
679           default:
680                     wpa_printf(MSG_INFO,
681                                  "Beacon request: Unknown measurement mode %d", mode);
682                     return -1;
683           }
684 
685           buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
686           if (!buf)
687                     return -1;
688 
689           hapd->beacon_req_token++;
690           if (!hapd->beacon_req_token)
691                     hapd->beacon_req_token++;
692 
693           wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
694           wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
695           wpabuf_put_u8(buf, hapd->beacon_req_token);
696           wpabuf_put_le16(buf, 0); /* Number of repetitions */
697 
698           /* Measurement Request element */
699           wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
700           wpabuf_put_u8(buf, 3 + wpabuf_len(req));
701           wpabuf_put_u8(buf, 1); /* Measurement Token */
702           wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
703           wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
704           wpabuf_put_buf(buf, req);
705 
706           ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
707                                               wpabuf_head(buf), wpabuf_len(buf));
708           wpabuf_free(buf);
709           if (ret < 0)
710                     return ret;
711 
712           return hapd->beacon_req_token;
713 }
714 
715 
hostapd_rrm_beacon_req_tx_status(struct hostapd_data * hapd,const struct ieee80211_mgmt * mgmt,size_t len,int ok)716 void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
717                                               const struct ieee80211_mgmt *mgmt,
718                                               size_t len, int ok)
719 {
720           if (len < 24 + 3)
721                     return;
722           wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
723                     " %u ack=%d", MAC2STR(mgmt->da),
724                     mgmt->u.action.u.rrm.dialog_token, ok);
725 }
726 
727 
hostapd_send_link_measurement_req(struct hostapd_data * hapd,const u8 * addr)728 int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr)
729 {
730           struct wpabuf *buf;
731           struct sta_info *sta;
732           int ret;
733 
734           wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR,
735                        MAC2STR(addr));
736 
737           if (!(hapd->iface->drv_rrm_flags &
738                 WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
739                     wpa_printf(MSG_INFO,
740                                  "Request Link Measurement: the driver does not support TX power insertion");
741                     return -1;
742           }
743 
744           sta = ap_get_sta(hapd, addr);
745           if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
746                     wpa_printf(MSG_INFO,
747                                  "Request Link Measurement: specied STA is not connected");
748                     return -1;
749           }
750 
751           if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) {
752                     wpa_printf(MSG_INFO,
753                                  "Request Link Measurement: destination STA does not support link measurement");
754                     return -1;
755           }
756 
757           if (hapd->link_mesr_req_active) {
758                     wpa_printf(MSG_DEBUG,
759                                  "Request Link Measurement: request already in process - overriding");
760                     hapd->link_mesr_req_active = 0;
761                     eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler,
762                                              hapd, NULL);
763           }
764 
765           /* Action + Action type + token + Tx Power used + Max Tx Power = 5 */
766           buf = wpabuf_alloc(5);
767           if (!buf)
768                     return -1;
769 
770           hapd->link_measurement_req_token++;
771           if (!hapd->link_measurement_req_token)
772                     hapd->link_measurement_req_token++;
773 
774           wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
775           wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
776           wpabuf_put_u8(buf, hapd->link_measurement_req_token);
777           /* NOTE: The driver is expected to fill the Tx Power Used and Max Tx
778            * Power */
779           wpabuf_put_u8(buf, 0);
780           wpabuf_put_u8(buf, 0);
781 
782           ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
783                                               wpabuf_head(buf), wpabuf_len(buf));
784           wpabuf_free(buf);
785           if (ret < 0)
786                     return ret;
787 
788           hapd->link_mesr_req_active = 1;
789 
790           eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
791                                      hostapd_link_mesr_rep_timeout_handler, hapd,
792                                      NULL);
793 
794           return hapd->link_measurement_req_token;
795 }
796