1849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt/* 2849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * hostapd / Radio Measurement (RRM) 3849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH. 4849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved. 5293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Copyright (c) 2016-2017, Jouni Malinen <j@w1.fi> 6849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * 7849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * This software may be distributed under the terms of the BSD license. 8849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * See README for more details. 9849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 10849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 11849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "utils/includes.h" 12849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 13849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "utils/common.h" 14293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "common/wpa_ctrl.h" 15849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "hostapd.h" 16849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "ap_drv_ops.h" 17849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "sta_info.h" 18849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "eloop.h" 19849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "neighbor_db.h" 20849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#include "rrm.h" 21849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 22849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt#define HOSTAPD_RRM_REQUEST_TIMEOUT 5 23849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 24849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 25849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx) 26849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 27849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct hostapd_data *hapd = eloop_data; 28849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 29849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out", 30849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_token); 31849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_active = 0; 32849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 33849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 34849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 35849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token, 36849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *pos, size_t len) 37849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 38849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!hapd->lci_req_active || hapd->lci_req_token != token) { 39849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token); 40849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 41849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 42849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 43849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_active = 0; 44849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL); 45849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len); 46849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 47849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 48849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 49849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx) 50849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 51849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct hostapd_data *hapd = eloop_data; 52849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 53849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out", 54849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_token); 55849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_active = 0; 56849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 57849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 58849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 59849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token, 60849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *pos, size_t len) 61849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 62849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!hapd->range_req_active || hapd->range_req_token != token) { 63849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "Unexpected range report, token %u", 64849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt token); 65849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 66849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 67849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 68849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_active = 0; 69849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); 70849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len); 71849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 72849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 73849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 74293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void hostapd_handle_beacon_report(struct hostapd_data *hapd, 75293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *addr, u8 token, u8 rep_mode, 76293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *pos, size_t len) 77293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 78293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt char report[2 * 255 + 1]; 79293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 80293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR, 81293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt token, len, MAC2STR(addr)); 82293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Skip to the beginning of the Beacon report */ 83293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < 3) 84293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 85293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos += 3; 86293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt len -= 3; 87293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report[0] = '\0'; 88293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0) 89293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 90293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", 91293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(addr), token, rep_mode, report); 92293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 93293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 94293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 95849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd, 96849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *buf, size_t len) 97849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 98849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; 99849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *pos, *ie, *end; 100293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 token, rep_mode; 101849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 102849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt end = buf + len; 103849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt token = mgmt->u.action.u.rrm.dialog_token; 104849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt pos = mgmt->u.action.u.rrm.variable; 105849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 106849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) { 107293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ie[1] < 3) { 108849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "Bad Measurement Report element"); 109849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 110849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 111849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 112293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep_mode = ie[3]; 113293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u", 114293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep_mode, ie[4]); 115849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 116849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt switch (ie[4]) { 117849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt case MEASURE_TYPE_LCI: 118849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]); 119849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 120849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt case MEASURE_TYPE_FTM_RANGE: 121849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_handle_range_report(hapd, token, ie + 2, ie[1]); 122849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 123293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case MEASURE_TYPE_BEACON: 124293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt hostapd_handle_beacon_report(hapd, mgmt->sa, token, 125293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep_mode, ie + 2, ie[1]); 126293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 127849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt default: 128849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 129849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Measurement report type %u is not supported", 130849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ie[4]); 131849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 132849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 133849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 134849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt pos = ie + ie[1] + 2; 135849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 136849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 137849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 138849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 139849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len) 140849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 141849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *subelem; 142849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 143849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Range Request element + Location Subject + Maximum Age subelement */ 144849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (len < 3 + 1 + 4) 145849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 146849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 147849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Subelements are arranged as IEs */ 148849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE); 149849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (subelem && subelem[1] == 2) 150ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return WPA_GET_LE16(subelem + 2); 151849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 152849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 153849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 154849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 155849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 156849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age) 157849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 158849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct os_time curr, diff; 159849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt unsigned long diff_l; 160849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 1619839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (nr->stationary || max_age == 0xffff) 1629839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return 1; 1639839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 164849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!max_age) 165849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 166849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 167849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (os_get_time(&curr)) 168849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 169849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 170849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_time_sub(&curr, &nr->lci_date, &diff); 171849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 172849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* avoid overflow */ 173849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (diff.sec > 0xffff) 174849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 175849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 176849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* LCI age is calculated in 10th of a second units. */ 177849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt diff_l = diff.sec * 10 + diff.usec / 100000; 178849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 179849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return max_age > diff_l; 180849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 181849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 182849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 183849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic size_t hostapd_neighbor_report_len(struct wpabuf *buf, 184849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct hostapd_neighbor_entry *nr, 185849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt int send_lci, int send_civic) 186849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 187849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt size_t len = 2 + wpabuf_len(nr->nr); 188849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 189849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (send_lci && nr->lci) 190849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len += 2 + wpabuf_len(nr->lci); 191849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 192849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (send_civic && nr->civic) 193849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len += 2 + wpabuf_len(nr->civic); 194849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 195849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return len; 196849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 197849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 198849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 199849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_send_nei_report_resp(struct hostapd_data *hapd, 200849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *addr, u8 dialog_token, 201849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_ssid_value *ssid, u8 lci, 202849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 civic, u16 lci_max_age) 203849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 204849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct hostapd_neighbor_entry *nr; 205849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpabuf *buf; 206849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 *msmt_token; 207849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 208849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 209849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * The number and length of the Neighbor Report elements in a Neighbor 210849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes 211849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * of RRM header. 212849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 213849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE); 214849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!buf) 215849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 216849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 217849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 218849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE); 219849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, dialog_token); 220849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 221849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, 222849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt list) { 223849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt int send_lci; 224849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt size_t len; 225849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 226849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ssid->ssid_len != nr->ssid.ssid_len || 227849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0) 228849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt continue; 229849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 230849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age); 231849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len = hostapd_neighbor_report_len(buf, nr, send_lci, civic); 232849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 233849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (len - 2 > 0xff) { 234849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 235849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "NR entry for " MACSTR " exceeds 0xFF bytes", 236849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt MAC2STR(nr->bssid)); 237849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt continue; 238849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 239849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 240849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (len > wpabuf_tailroom(buf)) 241849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 242849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 243849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); 244849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, len - 2); 245849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_buf(buf, nr->nr); 246849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 247849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (send_lci && nr->lci) { 248849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT); 249849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, wpabuf_len(nr->lci)); 250849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 251849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Override measurement token - the first byte of the 252849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Measurement Report element. 253849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 254849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt msmt_token = wpabuf_put(buf, 0); 255849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_buf(buf, nr->lci); 256849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt *msmt_token = lci; 257849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 258849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 259849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (civic && nr->civic) { 260849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT); 261849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, wpabuf_len(nr->civic)); 262849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 263849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Override measurement token - the first byte of the 264849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Measurement Report element. 265849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 266849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt msmt_token = wpabuf_put(buf, 0); 267849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_buf(buf, nr->civic); 268849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt *msmt_token = civic; 269849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 270849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 271849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 272849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, 273849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_head(buf), wpabuf_len(buf)); 274849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_free(buf); 275849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 276849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 277849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 278849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtstatic void hostapd_handle_nei_report_req(struct hostapd_data *hapd, 279849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *buf, size_t len) 280849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 281849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; 282849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *pos, *ie, *end; 283849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpa_ssid_value ssid = { 284849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt .ssid_len = 0 285849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt }; 286849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 token; 287849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 lci = 0, civic = 0; /* Measurement tokens */ 288849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u16 lci_max_age = 0; 289849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 290849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!(hapd->conf->radio_measurements[0] & 291849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt WLAN_RRM_CAPS_NEIGHBOR_REPORT)) 292849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 293849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 294849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt end = buf + len; 295849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 296849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt token = mgmt->u.action.u.rrm.dialog_token; 297849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt pos = mgmt->u.action.u.rrm.variable; 298849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len = end - pos; 299849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 300849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ie = get_ie(pos, len, WLAN_EID_SSID); 301849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) { 302849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ssid.ssid_len = ie[1]; 303849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len); 304849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } else { 305849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ssid.ssid_len = hapd->conf->ssid.ssid_len; 306849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); 307849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 308849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 309849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) { 310849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ie[1] < 3) 311849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 312849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 313849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 314849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Neighbor report request, measure type %u", 315849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ie[4]); 316849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 317849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt switch (ie[4]) { /* Measurement Type */ 318849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt case MEASURE_TYPE_LCI: 319849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt lci = ie[2]; /* Measurement Token */ 320849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt lci_max_age = hostapd_parse_location_lci_req_age(ie + 2, 321849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ie[1]); 322849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 323849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt case MEASURE_TYPE_LOCATION_CIVIC: 324849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt civic = ie[2]; /* Measurement token */ 325849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 326849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 327849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 328849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt pos = ie + ie[1] + 2; 329849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len = end - pos; 330849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 331849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 332849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic, 333849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt lci_max_age); 334849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 335849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 336849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 337849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtvoid hostapd_handle_radio_measurement(struct hostapd_data *hapd, 338849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *buf, size_t len) 339849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 340849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; 341849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 342849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 343849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Check for enough bytes: header + (1B)Category + (1B)Action + 344849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * (1B)Dialog Token. 345849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 346849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (len < IEEE80211_HDRLEN + 3) 347849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return; 348849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 349849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR, 350849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa)); 351849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 352849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt switch (mgmt->u.action.u.rrm.action) { 353849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt case WLAN_RRM_RADIO_MEASUREMENT_REPORT: 354849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_handle_radio_msmt_report(hapd, buf, len); 355849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 356849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt case WLAN_RRM_NEIGHBOR_REPORT_REQUEST: 357849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_handle_nei_report_req(hapd, buf, len); 358849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 359849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt default: 360849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "RRM action %u is not supported", 361849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt mgmt->u.action.u.rrm.action); 362849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt break; 363849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 364849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 365849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 366849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 367849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtint hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr) 368849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 369849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpabuf *buf; 370849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct sta_info *sta = ap_get_sta(hapd, addr); 371849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt int ret; 372849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 373ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { 374849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_INFO, 375849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Request LCI: Destination address is not connected"); 376849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 377849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 378849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 379849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) { 380849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_INFO, 381849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Request LCI: Station does not support LCI in RRM"); 382849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 383849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 384849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 385849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (hapd->lci_req_active) { 386849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 387849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Request LCI: LCI request is already in process, overriding"); 388849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_active = 0; 389849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, 390849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt NULL); 391849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 392849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 393849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Measurement request (5) + Measurement element with LCI (10) */ 394849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt buf = wpabuf_alloc(5 + 10); 395849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!buf) 396849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 397849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 398849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_token++; 399849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* For wraparounds - the token must be nonzero */ 400849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!hapd->lci_req_token) 401849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_token++; 402849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 403849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 404849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); 405849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, hapd->lci_req_token); 406849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_le16(buf, 0); /* Number of repetitions */ 407849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 408849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 409849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, 3 + 1 + 4); 410849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 411849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, 1); /* Measurement Token */ 412849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 413849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Parallel and Enable bits are 0, Duration, Request, and Report are 414849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * reserved. 415849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 416849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, 0); 417849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, MEASURE_TYPE_LCI); 418849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 419849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); 420849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 421849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); 422849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, 2); 423849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_le16(buf, 0xffff); 424849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 425849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, 426849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_head(buf), wpabuf_len(buf)); 427849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_free(buf); 428849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ret) 429849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return ret; 430849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 431849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_active = 1; 432849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 433849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, 434849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_lci_rep_timeout_handler, hapd, NULL); 435849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 436849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 437849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 438849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 439849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 440849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtint hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr, 441849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u16 random_interval, u8 min_ap, 442849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt const u8 *responders, unsigned int n_responders) 443849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 444849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct wpabuf *buf; 445849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct sta_info *sta; 446849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 *len; 447849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt unsigned int i; 448849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt int ret; 449849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 450849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR 451849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt " rand interval %u min AP %u n_responders %u", MAC2STR(addr), 452849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt random_interval, min_ap, n_responders); 453849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 454849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (min_ap == 0 || min_ap > n_responders) { 455849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_INFO, "Request range: Wrong min AP count"); 456849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 457849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 458849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 459849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt sta = ap_get_sta(hapd, addr); 460849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { 461849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_INFO, 462849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Request range: Destination address is not connected"); 463849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 464849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 465849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 466849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) { 467849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_ERROR, 468849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Request range: Destination station does not support FTM range report in RRM"); 469849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 470849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 471849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 472849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (hapd->range_req_active) { 473849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_DEBUG, 474849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt "Request range: Range request is already in process; overriding"); 475849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_active = 0; 476ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, 477ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt NULL); 478849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 479849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 480849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Action + measurement type + token + reps + EID + len = 7 */ 481849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt buf = wpabuf_alloc(7 + 255); 482849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!buf) 483849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 484849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 485849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_token++; 486849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!hapd->range_req_token) /* For wraparounds */ 487849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_token++; 488849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 489849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */ 490849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 491849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); 492849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */ 493849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_le16(buf, 0); /* Number of Repetitions */ 494849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 495849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */ 496849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 497849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len = wpabuf_put(buf, 1); /* Length will be set later */ 498849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 499849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, 1); /* Measurement Token */ 500849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 501849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Parallel and Enable bits are 0; Duration, Request, and Report are 502849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * reserved. 503849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 504849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ 505849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */ 506849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 507849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */ 508849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_le16(buf, random_interval); /* Randomization Interval */ 509849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */ 510849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 511849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* FTM Range Subelements */ 512849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 513849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* 514849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * Taking the neighbor report part of the range request from neighbor 515849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * database instead of requesting the separate bits of data from the 516849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt * user. 517849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt */ 518849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt for (i = 0; i < n_responders; i++) { 519849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt struct hostapd_neighbor_entry *nr; 520849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 521849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i, 522849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt NULL); 523849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (!nr) { 524849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_INFO, "Missing neighbor report for " 525849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt MACSTR, MAC2STR(responders + ETH_ALEN * i)); 526849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_free(buf); 527849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 528849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 529849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 530849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) { 531849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpa_printf(MSG_ERROR, "Too long range request"); 532849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_free(buf); 533849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return -1; 534849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 535849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 536849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); 537849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_u8(buf, wpabuf_len(nr->nr)); 538849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_put_buf(buf, nr->nr); 539849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt } 540849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 541849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt /* Action + measurement type + token + reps + EID + len = 7 */ 542849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt *len = wpabuf_len(buf) - 7; 543849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 544849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, 545849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_head(buf), wpabuf_len(buf)); 546849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt wpabuf_free(buf); 547849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ret) 548849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return ret; 549849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 550849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_active = 1; 551849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 552849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, 553849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostapd_range_rep_timeout_handler, hapd, NULL); 554849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 555849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt return 0; 556849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 557849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 558849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 559849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtvoid hostapd_clean_rrm(struct hostapd_data *hapd) 560849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{ 561849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hostpad_free_neighbor_db(hapd); 562849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL); 563849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->lci_req_active = 0; 564849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); 565849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt hapd->range_req_active = 0; 566849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt} 567293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 568293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 569293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtint hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr, 570293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 req_mode, const struct wpabuf *req) 571293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 572293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *buf; 573293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct sta_info *sta = ap_get_sta(hapd, addr); 574293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int ret; 575293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt enum beacon_report_mode mode; 576293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *pos; 577293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 578293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Request data: 579293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Operating Class (1), Channel Number (1), Randomization Interval (2), 580293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Measurement Duration (2), Measurement Mode (1), BSSID (6), 581293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Optional Subelements (variable) 582293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 583293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpabuf_len(req) < 13) { 584293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, "Beacon request: Too short request data"); 585293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 586293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 587293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos = wpabuf_head(req); 588293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt mode = pos[6]; 589293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 590293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { 591293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 592293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: " MACSTR " is not connected", 593293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(addr)); 594293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 595293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 596293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 597293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt switch (mode) { 598293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case BEACON_REPORT_MODE_PASSIVE: 599293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(sta->rrm_enabled_capa[0] & 600293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) { 601293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 602293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: " MACSTR 603293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt " does not support passive beacon report", 604293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(addr)); 605293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 606293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 607293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 608293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case BEACON_REPORT_MODE_ACTIVE: 609293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(sta->rrm_enabled_capa[0] & 610293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) { 611293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 612293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: " MACSTR 613293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt " does not support active beacon report", 614293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(addr)); 615293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 616293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 617293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 618293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case BEACON_REPORT_MODE_TABLE: 619293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(sta->rrm_enabled_capa[0] & 620293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) { 621293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 622293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: " MACSTR 623293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt " does not support table beacon report", 624293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(addr)); 625293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 626293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 627293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 628293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt default: 629293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 630293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: Unknown measurement mode %d", mode); 631293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 632293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 633293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 634293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req)); 635293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!buf) 636293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 637293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 638293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt hapd->beacon_req_token++; 639293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!hapd->beacon_req_token) 640293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt hapd->beacon_req_token++; 641293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 642293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 643293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); 644293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, hapd->beacon_req_token); 645293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_le16(buf, 0); /* Number of repetitions */ 646293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 647293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Measurement Request element */ 648293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 649293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 3 + wpabuf_len(req)); 650293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 1); /* Measurement Token */ 651293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */ 652293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */ 653293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_buf(buf, req); 654293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 655293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, 656293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_head(buf), wpabuf_len(buf)); 657293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 658293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ret < 0) 659293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return ret; 660293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 661293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return hapd->beacon_req_token; 662293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 663293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 664293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 665293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtvoid hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, 666293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct ieee80211_mgmt *mgmt, 667293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t len, int ok) 668293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 669293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < 24 + 3) 670293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 671293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR 672293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt " %u ack=%d", MAC2STR(mgmt->da), 673293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt mgmt->u.action.u.rrm.dialog_token, ok); 674293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 675