Home | History | Annotate | Line # | Download | only in ap
      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 (at) 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 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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