1293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/* 2293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * wpa_supplicant - Radio Measurements 3293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> 4293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * 5293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * See README for more details. 7293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 8293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 9293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "includes.h" 10293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 11293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "utils/common.h" 12293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "utils/eloop.h" 13293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "common/ieee802_11_common.h" 14293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "wpa_supplicant_i.h" 15293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "driver_i.h" 16293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "bss.h" 17293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "scan.h" 18293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#include "p2p_supplicant.h" 19293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 20293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 21293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx) 22293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 23293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct rrm_data *rrm = data; 24293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 25293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!rrm->notify_neighbor_rep) { 26293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_ERROR, 27293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Unexpected neighbor report timeout"); 28293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 29293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 30293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 31293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE"); 32293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL); 33293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 34293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rrm->notify_neighbor_rep = NULL; 35293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rrm->neighbor_rep_cb_ctx = NULL; 36293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 37293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 38293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 39293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/* 40293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant 41293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant 42293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 43293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtvoid wpas_rrm_reset(struct wpa_supplicant *wpa_s) 44293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 45293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.rrm_used = 0; 46293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 47293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, 48293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NULL); 49293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_s->rrm.notify_neighbor_rep) 50293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); 51293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.next_neighbor_rep_token = 1; 52293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_clear_beacon_rep_data(wpa_s); 53293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 54293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 55293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 56293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/* 57293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report 58293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant 59293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @report: Neighbor report buffer, prefixed by a 1-byte dialog token 60293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @report_len: Length of neighbor report buffer 61293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 62293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtvoid wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, 63293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *report, size_t report_len) 64293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 65293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *neighbor_rep; 66293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 67293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len); 68293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (report_len < 1) 69293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 70293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 71293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) { 72293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 73293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Discarding neighbor report with token %d (expected %d)", 74293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report[0], wpa_s->rrm.next_neighbor_rep_token - 1); 75293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 76293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 77293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 78293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm, 79293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NULL); 80293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 81293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->rrm.notify_neighbor_rep) { 82293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report"); 83293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 84293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 85293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 86293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* skipping the first byte, which is only an id (dialog token) */ 87293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt neighbor_rep = wpabuf_alloc(report_len - 1); 88293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!neighbor_rep) { 89293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL); 90293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 91293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 92293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_data(neighbor_rep, report + 1, report_len - 1); 93293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)", 94293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report[0]); 95293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx, 96293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt neighbor_rep); 97293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.notify_neighbor_rep = NULL; 98293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.neighbor_rep_cb_ctx = NULL; 99293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 100293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 101293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 102293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) 103293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/* Workaround different, undefined for Windows, error codes used here */ 104293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#define ENOTCONN -1 105293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#define EOPNOTSUPP -1 106293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#define ECANCELED -1 107293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#endif 108293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 109293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/* Measurement Request element + Location Subject + Maximum Age subelement */ 110293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4) 111293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/* Measurement Request element + Location Civic Request */ 112293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#define MEASURE_REQUEST_CIVIC_LEN (3 + 5) 113293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 114293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 115293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/** 116293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP 117293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @wpa_s: Pointer to wpa_supplicant 118293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE 119293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * is sent in the request. 120293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @lci: if set, neighbor request will include LCI request 121293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @civic: if set, neighbor request will include civic location request 122293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @cb: Callback function to be called once the requested report arrives, or 123293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds. 124293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's 125293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * the requester's responsibility to free it. 126293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * In the latter case NULL will be sent in 'neighbor_rep'. 127293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * @cb_ctx: Context value to send the callback function 128293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Returns: 0 in case of success, negative error code otherwise 129293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * 130293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * In case there is a previous request which has not been answered yet, the 131293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT. 132293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Request must contain a callback function. 133293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 134293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtint wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, 135293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct wpa_ssid_value *ssid, 136293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int lci, int civic, 137293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt void (*cb)(void *ctx, 138293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *neighbor_rep), 139293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt void *cb_ctx) 140293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 141293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *buf; 142293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *rrm_ie; 143293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 144293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) { 145293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM."); 146293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -ENOTCONN; 147293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 148293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 149293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->rrm.rrm_used) { 150293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection."); 151293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -EOPNOTSUPP; 152293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 153293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 154293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rrm_ie = wpa_bss_get_ie(wpa_s->current_bss, 155293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WLAN_EID_RRM_ENABLED_CAPABILITIES); 156293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) || 157293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) { 158293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 159293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: No network support for Neighbor Report."); 160293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -EOPNOTSUPP; 161293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 162293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 163293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Refuse if there's a live request */ 164293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_s->rrm.notify_neighbor_rep) { 165293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 166293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Currently handling previous Neighbor Report."); 167293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -EBUSY; 168293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 169293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 170293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 3 = action category + action code + dialog token */ 171293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) + 172293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) + 173293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0)); 174293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (buf == NULL) { 175293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 176293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Failed to allocate Neighbor Report Request"); 177293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -ENOMEM; 178293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 179293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 180293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d", 181293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""), 182293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.next_neighbor_rep_token); 183293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 184293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 185293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST); 186293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token); 187293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ssid) { 188293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_SSID); 189293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, ssid->ssid_len); 190293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len); 191293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 192293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 193293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (lci) { 194293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ 195293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 196293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN); 197293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 198293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 199293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Measurement token; nonzero number that is unique among the 200293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Measurement Request elements in a particular frame. 201293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 202293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 1); /* Measurement Token */ 203293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 204293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 205293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Parallel, Enable, Request, and Report bits are 0, Duration is 206293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * reserved. 207293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 208293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ 209293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */ 210293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 211293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */ 212293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Location Subject */ 213293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); 214293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 215293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Optional Subelements */ 216293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 217293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * IEEE P802.11-REVmc/D5.0 Figure 9-170 218293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * The Maximum Age subelement is required, otherwise the AP can 219293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * send only data that was determined after receiving the 220293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * request. Setting it here to unlimited age. 221293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 222293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); 223293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 2); 224293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_le16(buf, 0xffff); 225293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 226293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 227293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (civic) { 228293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ 229293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); 230293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN); 231293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 232293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 233293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Measurement token; nonzero number that is unique among the 234293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Measurement Request elements in a particular frame. 235293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 236293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 2); /* Measurement Token */ 237293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 238293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 239293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Parallel, Enable, Request, and Report bits are 0, Duration is 240293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * reserved. 241293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 242293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ 243293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Measurement Type */ 244293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC); 245293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 246293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14: 247293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Location Civic request */ 248293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Location Subject */ 249293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); 250293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */ 251293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Location Service Interval Units: Seconds */ 252293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, 0); 253293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Location Service Interval: 0 - Only one report is requested 254293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 255293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_le16(buf, 0); 256293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* No optional subelements */ 257293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 258293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 259293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.next_neighbor_rep_token++; 260293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 261293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 262293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 263293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_head(buf), wpabuf_len(buf), 0) < 0) { 264293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 265293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Failed to send Neighbor Report Request"); 266293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 267293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -ECANCELED; 268293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 269293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 270293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx; 271293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.notify_neighbor_rep = cb; 272293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0, 273293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_neighbor_rep_timeout_handler, 274293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt &wpa_s->rrm, NULL); 275293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 276293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 277293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 278293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 279293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 280293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 281092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartstatic int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type, 282293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *data, size_t data_len) 283293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 284092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart if (wpabuf_resize(buf, 5 + data_len)) 285293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 286293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 287092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT); 288092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpabuf_put_u8(*buf, 3 + data_len); 289092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpabuf_put_u8(*buf, token); 290092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpabuf_put_u8(*buf, mode); 291092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpabuf_put_u8(*buf, type); 292293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 293293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (data_len) 294092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpabuf_put_data(*buf, data, data_len); 295293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 296293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 297293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 298293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 299293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 300293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int 301293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtwpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s, 302293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct rrm_measurement_request_element *req, 303293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf **buf) 304293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 305293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 subject; 306293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u16 max_age = 0; 307293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct os_reltime t, diff; 308293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt unsigned long diff_l; 309293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *subelem; 310293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *request = req->variable; 311293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t len = req->len - 3; 312293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 313293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < 1) 314293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 315293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 316293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->lci) 317293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto reject; 318293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 319293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subject = *request++; 320293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt len--; 321293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 322293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Measurement request location subject=%u", 323293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subject); 324293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 325293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (subject != LOCATION_SUBJECT_REMOTE) { 326293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 327293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Not building LCI report - bad location subject"); 328293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 329293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 330293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 331293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Subelements are formatted exactly like elements */ 332293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "LCI request subelements", request, len); 333293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE); 334293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (subelem && subelem[1] == 2) 335293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt max_age = WPA_GET_LE16(subelem + 2); 336293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 337293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (os_get_reltime(&t)) 338293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto reject; 339293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 340293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_reltime_sub(&t, &wpa_s->lci_time, &diff); 341293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* LCI age is calculated in 10th of a second units. */ 342293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt diff_l = diff.sec * 10 + diff.usec / 100000; 343293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 344293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (max_age != 0xffff && max_age < diff_l) 345293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto reject; 346293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 347092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart if (wpas_rrm_report_elem(buf, req->token, 348293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MEASUREMENT_REPORT_MODE_ACCEPT, req->type, 349293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_head_u8(wpa_s->lci), 350293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_len(wpa_s->lci)) < 0) { 351293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to add LCI report element"); 352293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 353293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 354293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 355293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 356293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 357293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtreject: 358d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && 359d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpas_rrm_report_elem(buf, req->token, 360293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE, 361293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->type, NULL, 0) < 0) { 362293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); 363293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 364293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 365293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 366293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 367293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 368293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 369293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 370293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s, 371293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *data, size_t len) 372293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 373293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *report = wpabuf_alloc(len + 3); 374293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 375293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!report) 376293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 377293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 378293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT); 379293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT); 380293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(report, wpa_s->rrm.token); 381293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 382293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_data(report, data, len); 383293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 384293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 385293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 386293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_head(report), wpabuf_len(report), 0)) { 387293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_ERROR, 388293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Radio measurement report failed: Sending Action frame failed"); 389293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 390293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 391293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(report); 392293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 393293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 394293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 395293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s, 396293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *buf) 397293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 398293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int len = wpabuf_len(buf); 399293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *pos = wpabuf_head_u8(buf), *next = pos; 400293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 401293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3) 402293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 403293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt while (len) { 404293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len; 405293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 406293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (send_len == len || 407293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (send_len + next[1] + 2) > MPDU_REPORT_LEN) { 408293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len); 409293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt len -= send_len; 410293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos = next; 411293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 412293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 413d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (len) 414d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt next += next[1] + 2; 415293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 416293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt#undef MPDU_REPORT_LEN 417293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 418293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 419293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 420293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels, 421293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int *freqs) 422293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 423293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t i; 424293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 425293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt for (i = 0; i < num_primary_channels; i++) { 426293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4; 427293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 428293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan); 429092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart /* ieee80211_chan_to_freq() is not really meant for this 430092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * conversion of 20 MHz primary channel numbers for wider VHT 431092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * channels, so handle those as special cases here for now. */ 432092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart if (freqs[i] < 0 && 433092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart (op_class == 128 || op_class == 129 || op_class == 130)) 434092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart freqs[i] = 5000 + 5 * primary_chan; 435293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (freqs[i] < 0) { 436293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 437293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon Report: Invalid channel %u", 438293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt chan); 439293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 440293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 441293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 442293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 443293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 444293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 445293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 446293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 447293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int * wpas_add_channels(const struct oper_class_map *op, 448293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct hostapd_hw_modes *mode, int active, 449293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *channels, const u8 size) 450293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 451293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int *freqs, *next_freq; 452293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 num_primary_channels, i; 453293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 num_chans; 454293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 455293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt num_chans = channels ? size : 456293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (op->max_chan - op->min_chan) / op->inc + 1; 457293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 458293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (op->bw == BW80 || op->bw == BW80P80) 459293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt num_primary_channels = 4; 460293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt else if (op->bw == BW160) 461293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt num_primary_channels = 8; 462293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt else 463293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt num_primary_channels = 1; 464293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 465293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* one extra place for the zero-terminator */ 466293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt freqs = os_calloc(num_chans * num_primary_channels + 1, sizeof(*freqs)); 467293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!freqs) { 468293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_ERROR, 469293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon Report: Failed to allocate freqs array"); 470293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 471293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 472293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 473293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt next_freq = freqs; 474293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt for (i = 0; i < num_chans; i++) { 475293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 chan = channels ? channels[i] : op->min_chan + i * op->inc; 476293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt enum chan_allowed res = verify_channel(mode, chan, op->bw); 477293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 478293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (res == NOT_ALLOWED || (res == NO_IR && active)) 479293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt continue; 480293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 481293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpas_add_channel(op->op_class, chan, num_primary_channels, 482293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt next_freq) < 0) { 483293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_free(freqs); 484293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 485293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 486293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 487293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt next_freq += num_primary_channels; 488293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 489293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 490293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!freqs[0]) { 491293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_free(freqs); 492293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 493293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 494293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 495293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return freqs; 496293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 497293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 498293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 499293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int * wpas_op_class_freqs(const struct oper_class_map *op, 500293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct hostapd_hw_modes *mode, int active) 501293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 502293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 }; 503293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 channels_160mhz[] = { 50, 114 }; 504293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 505293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 506293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * When adding all channels in the operating class, 80 + 80 MHz 507293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * operating classes are like 80 MHz channels because we add all valid 508293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * channels anyway. 509293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 510293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (op->bw == BW80 || op->bw == BW80P80) 511293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return wpas_add_channels(op, mode, active, channels_80mhz, 512293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ARRAY_SIZE(channels_80mhz)); 513293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 514293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (op->bw == BW160) 515293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return wpas_add_channels(op, mode, active, channels_160mhz, 516293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ARRAY_SIZE(channels_160mhz)); 517293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 518293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return wpas_add_channels(op, mode, active, NULL, 0); 519293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 520293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 521293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 522293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, 523293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const char *country, const u8 *subelems, 524293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t len) 525293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 526293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int *freqs = NULL, *new_freqs; 527293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *end = subelems + len; 528293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 529293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt while (end - subelems > 2) { 530293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct oper_class_map *op; 531293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *ap_chan_elem, *pos; 532293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 left; 533293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct hostapd_hw_modes *mode; 534293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 535293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ap_chan_elem = get_ie(subelems, end - subelems, 536293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL); 537293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!ap_chan_elem) 538293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 539293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos = ap_chan_elem + 2; 540293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt left = ap_chan_elem[1]; 541293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (left < 1) 542293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 543293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subelems = ap_chan_elem + 2 + left; 544293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 545293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt op = get_oper_class(country, *pos); 546293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!op) { 547293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 548293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: unknown operating class in AP Channel Report subelement %u", 549293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt *pos); 550293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 551293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 552293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos++; 553293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt left--; 554293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 555293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode); 556293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!mode) 557293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt continue; 558293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 559293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 560293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * For 80 + 80 MHz operating classes, this AP Channel Report 561293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * element should be followed by another element specifying 562293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * the second 80 MHz channel. For now just add this 80 MHz 563293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * channel, the second 80 MHz channel will be added when the 564293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * next element is parsed. 565293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * TODO: Verify that this AP Channel Report element is followed 566293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * by a corresponding AP Channel Report element as specified in 567293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * IEEE Std 802.11-2016, 11.11.9.1. 568293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 569293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt new_freqs = wpas_add_channels(op, mode, active, pos, left); 570293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (new_freqs) 571293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int_array_concat(&freqs, new_freqs); 572293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 573293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_free(new_freqs); 574293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 575293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 576293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return freqs; 577293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtout: 578293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_free(freqs); 579293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 580293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 581293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 582293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 583293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, 584293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 op_class, u8 chan, int active, 585293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *subelems, size_t len) 586293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 587293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int *freqs = NULL, *ext_freqs = NULL; 588293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct hostapd_hw_modes *mode; 589293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const char *country = NULL; 590293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct oper_class_map *op; 591293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *elem; 592293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 593293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->current_bss) 594293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 595293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt elem = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY); 596293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (elem && elem[1] >= 2) 597293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt country = (const char *) (elem + 2); 598293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 599293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt op = get_oper_class(country, op_class); 600293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!op) { 601293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 602293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: invalid operating class %d", 603293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt op_class); 604293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 605293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 606293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 607293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode); 608293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!mode) 609293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 610293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 611293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt switch (chan) { 612293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case 0: 613293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt freqs = wpas_op_class_freqs(op, mode, active); 614293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!freqs) 615293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 616293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 617293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case 255: 618293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* freqs will be added from AP channel subelements */ 619293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 620293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt default: 621293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt freqs = wpas_add_channels(op, mode, active, &chan, 1); 622293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!freqs) 623293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 624293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 625293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 626293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 627293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems, 628293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt len); 629293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ext_freqs) { 630293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int_array_concat(&freqs, ext_freqs); 631293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_free(ext_freqs); 632d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt int_array_sort_unique(freqs); 633293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 634293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 635293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return freqs; 636293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 637293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 638293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 639092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewartstatic int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len, 640092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart u8 *op_class, u8 *chan, u8 *phy_type) 641293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 642293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *ie; 643293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int sec_chan = 0, vht = 0; 644293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct ieee80211_ht_operation *ht_oper = NULL; 645293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct ieee80211_vht_operation *vht_oper = NULL; 646293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 seg0, seg1; 647293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 648293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); 649293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ie && ie[1] >= sizeof(struct ieee80211_ht_operation)) { 650293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 sec_chan_offset; 651293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 652293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ht_oper = (struct ieee80211_ht_operation *) (ie + 2); 653293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt sec_chan_offset = ht_oper->ht_param & 654293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; 655293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (sec_chan_offset == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) 656293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt sec_chan = 1; 657293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt else if (sec_chan_offset == 658293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) 659293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt sec_chan = -1; 660293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 661293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 662293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); 663293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ie && ie[1] >= sizeof(struct ieee80211_vht_operation)) { 664293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht_oper = (struct ieee80211_vht_operation *) (ie + 2); 665293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 666293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt switch (vht_oper->vht_op_info_chwidth) { 667293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case 1: 668293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx; 669293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx; 670293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (seg1 && abs(seg1 - seg0) == 8) 671293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht = VHT_CHANWIDTH_160MHZ; 672293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt else if (seg1) 673293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht = VHT_CHANWIDTH_80P80MHZ; 674293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt else 675293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht = VHT_CHANWIDTH_80MHZ; 676293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 677293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case 2: 678293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht = VHT_CHANWIDTH_160MHZ; 679293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 680293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case 3: 681293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht = VHT_CHANWIDTH_80P80MHZ; 682293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 683293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt default: 684293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht = VHT_CHANWIDTH_USE_HT; 685293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 686293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 687293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 688293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 689293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ieee80211_freq_to_channel_ext(freq, sec_chan, vht, op_class, 690293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt chan) == NUM_HOSTAPD_MODES) { 691293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 692293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Cannot determine operating class and channel"); 693293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 694293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 695293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 696293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt *phy_type = ieee80211_get_phy_type(freq, ht_oper != NULL, 697293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt vht_oper != NULL); 698293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (*phy_type == PHY_TYPE_UNSPECIFIED) { 699293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Cannot determine phy type"); 700293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 701293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 702293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 703293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 704293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 705293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 706293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 707293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int wpas_beacon_rep_add_frame_body(struct bitfield *eids, 708293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt enum beacon_report_detail detail, 709293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_bss *bss, u8 *buf, 710293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t buf_len) 711293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 712293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 *ies = (u8 *) (bss + 1); 713293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; 714293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 *pos = buf; 715293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int rem_len; 716293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 717293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) - 718293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt sizeof(struct rrm_measurement_report_element) - 2; 719293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 720293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) { 721293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 722293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon Request: Invalid reporting detail: %d", 723293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt detail); 724293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 725293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 726293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 727293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (detail == BEACON_REPORT_DETAIL_NONE) 728293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 729293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 730293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 731293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) + 732293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * beacon interval(2) + capabilities(2) = 14 bytes 733293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 734293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (buf_len < 14) 735293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 736293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 737293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt *pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY; 738293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* The length will be filled later */ 739293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos++; 740293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WPA_PUT_LE64(pos, bss->tsf); 741293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos += sizeof(bss->tsf); 742293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WPA_PUT_LE16(pos, bss->beacon_int); 743293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos += 2; 744293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WPA_PUT_LE16(pos, bss->caps); 745293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos += 2; 746293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 747293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rem_len -= pos - buf; 748293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 749293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 750293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame 751293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * body subelement causes the element to exceed the maximum element 752293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * size, the subelement is truncated so that the last IE is a complete 753293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * IE. So even when required to report all IEs, add elements one after 754293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * the other and stop once there is no more room in the measurement 755293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * element. 756293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 757293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) { 758293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS || 759293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (eids && bitfield_is_set(eids, ies[0]))) { 760293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 eid = ies[0], elen = ies[1]; 761293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 762293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if ((eid == WLAN_EID_TIM || eid == WLAN_EID_RSN) && 763293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt elen > 4) 764293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt elen = 4; 765293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* 766293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * TODO: Truncate IBSS DFS element as described in 767293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * IEEE Std 802.11-2016, 9.4.2.22.7. 768293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 769293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 770293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (2 + elen > buf + buf_len - pos || 771293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 2 + elen > rem_len) 772293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 773293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 774293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt *pos++ = ies[0]; 775293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt *pos++ = elen; 776293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcpy(pos, ies + 2, elen); 777293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos += elen; 778293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rem_len -= 2 + elen; 779293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 780293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 781293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ies_len -= 2 + ies[1]; 782293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ies += 2 + ies[1]; 783293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 784293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 785293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Now the length is known */ 786293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt buf[1] = pos - buf - 2; 787293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return pos - buf; 788293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 789293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 790293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 791293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s, 792293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf **wpa_buf, struct wpa_bss *bss, 793293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u64 start, u64 parent_tsf) 794293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 795293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct beacon_rep_data *data = &wpa_s->beacon_rep_data; 796293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 *ie = (u8 *) (bss + 1); 797293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t ie_len = bss->ie_len + bss->beacon_ie_len; 798293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int ret; 799d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt u8 *buf; 800293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct rrm_measurement_beacon_report *rep; 801293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 802293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 && 803293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0) 804293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 805293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 806293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (data->ssid_len && 807293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (data->ssid_len != bss->ssid_len || 808293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0)) 809293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 810293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 811d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt /* Maximum element length: beacon report element + reported frame body 812d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * subelement + all IEs of the reported beacon */ 813d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt buf = os_malloc(sizeof(*rep) + 14 + ie_len); 814d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!buf) 815d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return -1; 816d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 817293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep = (struct rrm_measurement_beacon_report *) buf; 818293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpas_get_op_chan_phy(bss->freq, ie, ie_len, &rep->op_class, 819d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt &rep->channel, &rep->report_info) < 0) { 820d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ret = 0; 821d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto out; 822d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 823293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 824293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep->start_time = host_to_le64(start); 825293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep->duration = host_to_le16(data->scan_params.duration); 826293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep->rcpi = rssi_to_rcpi(bss->level); 827293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep->rsni = 255; /* 255 indicates that RSNI is not available */ 828293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcpy(rep->bssid, bss->bssid, ETH_ALEN); 829293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep->antenna_id = 0; /* unknown */ 830293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rep->parent_tsf = host_to_le32(parent_tsf); 831293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 832293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail, 833d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt bss, rep->variable, 14 + ie_len); 834293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ret < 0) 835d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto out; 836293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 837d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ret = wpas_rrm_report_elem(wpa_buf, wpa_s->beacon_rep_data.token, 838d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt MEASUREMENT_REPORT_MODE_ACCEPT, 839d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt MEASURE_TYPE_BEACON, buf, 840d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ret + sizeof(*rep)); 841d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtout: 842d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_free(buf); 843d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return ret; 844293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 845293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 846293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 847293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s, 848293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf **buf) 849293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 850092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token, 851293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MEASUREMENT_REPORT_MODE_ACCEPT, 852293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MEASURE_TYPE_BEACON, NULL, 0); 853293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 854293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 855293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 856293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s, 857293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf **buf) 858293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 859293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t i; 860293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 861293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt for (i = 0; i < wpa_s->last_scan_res_used; i++) { 862293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i], 863293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 0, 0) < 0) 864293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 865293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 866293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 867293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(*buf)) 868293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_beacon_rep_no_results(wpa_s, buf); 869293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 870293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf); 871293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 872293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 873293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 874d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtvoid wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s) 875293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 876d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) { 877d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt struct wpabuf *buf = NULL; 878d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt 879d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token, 880d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt MEASUREMENT_REPORT_MODE_REJECT_REFUSED, 881d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt MEASURE_TYPE_BEACON, NULL, 0)) { 882d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpa_printf(MSG_ERROR, "RRM: Memory allocation failed"); 883d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpabuf_free(buf); 884d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return; 885d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 886293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 887d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpas_rrm_send_msr_report(wpa_s, buf); 888293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 889293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 890293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 891293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_clear_beacon_rep_data(wpa_s); 892293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 893293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 894293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 895293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx) 896293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 897293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_supplicant *wpa_s = eloop_ctx; 898293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_driver_scan_params *params = 899293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt &wpa_s->beacon_rep_data.scan_params; 900293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u16 prev_duration = params->duration; 901293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 902293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->current_bss) 903293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 904293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 905293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) && 906293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->duration) { 907293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 908293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Cannot set scan duration due to missing driver support"); 909293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->duration = 0; 910293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 911293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_get_reltime(&wpa_s->beacon_rep_scan); 912293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) || 913293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_supplicant_trigger_scan(wpa_s, params)) 914293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_refuse_request(wpa_s); 915293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->duration = prev_duration; 916293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 917293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 918293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 919293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s, 920293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct beacon_rep_data *data, 921293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 sid, u8 slen, const u8 *subelem) 922293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 923293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 report_info, i; 924293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 925293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt switch (sid) { 926293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case WLAN_BEACON_REQUEST_SUBELEM_SSID: 927293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!slen) { 928293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 929293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "SSID subelement with zero length - wildcard SSID"); 930293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 931293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 932293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 933293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (slen > SSID_MAX_LEN) { 934293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 935293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Invalid SSID subelement length: %u", slen); 936293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 937293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 938293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 939293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt data->ssid_len = slen; 940293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcpy(data->ssid, subelem, data->ssid_len); 941293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 942293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case WLAN_BEACON_REQUEST_SUBELEM_INFO: 943293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (slen != 2) { 944293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 945293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Invalid reporting information subelement length: %u", 946293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt slen); 947293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 948293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 949293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 950293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report_info = subelem[0]; 951293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (report_info != 0) { 952293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 953293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "reporting information=%u is not supported", 954293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report_info); 955293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 956293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 957293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 958293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case WLAN_BEACON_REQUEST_SUBELEM_DETAIL: 959293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (slen != 1) { 960293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 961293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Invalid reporting detail subelement length: %u", 962293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt slen); 963293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 964293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 965293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 966293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt data->report_detail = subelem[0]; 967293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (data->report_detail > 968293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) { 969293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u", 970293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subelem[0]); 971d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt return -1; 972293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 973293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 974293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 975293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case WLAN_BEACON_REQUEST_SUBELEM_REQUEST: 976293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (data->report_detail != 977293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt BEACON_REPORT_DETAIL_REQUESTED_ONLY) { 978293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 979293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: request subelement is present but report detail is %u", 980293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt data->report_detail); 981293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 982293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 983293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 984293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!slen) { 985293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 986293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Invalid request subelement length: %u", 987293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt slen); 988293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 989293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 990293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 991293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (data->eids) { 992293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 993293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon Request: Request subelement appears more than once"); 994293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 995293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 996293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 997293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt data->eids = bitfield_alloc(255); 998293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!data->eids) { 999293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap"); 1000293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 1001293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1002293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1003293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt for (i = 0; i < slen; i++) 1004293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt bitfield_set(data->eids, subelem[i]); 1005293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 1006293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL: 1007293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Skip - it will be processed when freqs are added */ 1008293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 1009293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt default: 1010293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1011293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon request: Unknown subelement id %u", sid); 1012293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 1013293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1014293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1015293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 1; 1016293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1017293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1018293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1019293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt/** 1020293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * Returns 0 if the next element can be processed, 1 if some operation was 1021293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * triggered, and -1 if processing failed (i.e., the element is in invalid 1022293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * format or an internal error occurred). 1023293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt */ 1024293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int 1025293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtwpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s, 1026293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u8 elem_token, int duration_mandatory, 1027293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct rrm_measurement_beacon_request *req, 1028293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t len, struct wpabuf **buf) 1029293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1030293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct beacon_rep_data *data = &wpa_s->beacon_rep_data; 1031293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_driver_scan_params *params = &data->scan_params; 1032293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *subelems; 1033293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t elems_len; 1034293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u16 rand_interval; 1035293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u32 interval_usec; 1036293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt u32 _rand; 1037293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int ret = 0, res; 1038d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt u8 reject_mode; 1039293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1040293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < sizeof(*req)) 1041293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 1042293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1043293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->mode != BEACON_REPORT_MODE_PASSIVE && 1044293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->mode != BEACON_REPORT_MODE_ACTIVE && 1045293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->mode != BEACON_REPORT_MODE_TABLE) 1046293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 1047293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1048293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subelems = req->variable; 1049293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt elems_len = len - sizeof(*req); 1050293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt rand_interval = le_to_host16(req->rand_interval); 1051293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1052ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt os_free(params->freqs); 1053293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memset(params, 0, sizeof(*params)); 1054293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1055293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt data->token = elem_token; 1056293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1057293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* default reporting detail is all fixed length fields and all 1058293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * elements */ 1059293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS; 1060293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcpy(data->bssid, req->bssid, ETH_ALEN); 1061293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1062293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt while (elems_len >= 2) { 1063293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (subelems[1] > elems_len - 2) { 1064293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1065293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "Beacon Request: Truncated subelement"); 1066293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ret = -1; 1067293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1068293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1069293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1070293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt res = wpas_rm_handle_beacon_req_subelem( 1071293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s, data, subelems[0], subelems[1], &subelems[2]); 1072d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (res < 0) { 1073293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ret = res; 1074293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1075d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } else if (!res) { 1076d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE; 1077d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto out_reject; 1078293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1079293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1080293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt elems_len -= 2 + subelems[1]; 1081293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt subelems += 2 + subelems[1]; 1082293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1083293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1084293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->mode == BEACON_REPORT_MODE_TABLE) { 1085293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_beacon_rep_table(wpa_s, buf); 1086293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1087293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1088293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1089293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->freqs = wpas_beacon_request_freqs( 1090293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s, req->oper_class, req->channel, 1091293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->mode == BEACON_REPORT_MODE_ACTIVE, 1092293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->variable, len - sizeof(*req)); 1093293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!params->freqs) { 1094293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Beacon request: No valid channels"); 1095d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED; 1096d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt goto out_reject; 1097293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1098293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1099293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->duration = le_to_host16(req->duration); 1100293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->duration_mandatory = duration_mandatory; 1101293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!params->duration) { 1102293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0"); 1103293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ret = -1; 1104293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1105293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1106293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1107293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->only_new_results = 1; 1108293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1109293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->mode == BEACON_REPORT_MODE_ACTIVE) { 1110293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->ssids[params->num_ssids].ssid = data->ssid; 1111293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt params->ssids[params->num_ssids++].ssid_len = data->ssid_len; 1112293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1113293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1114293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) 1115293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt _rand = os_random(); 1116293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt interval_usec = (_rand % (rand_interval + 1)) * 1024; 1117293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s, 1118293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NULL); 1119293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 1; 1120d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtout_reject: 1121d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && 1122d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpas_rrm_report_elem(buf, elem_token, reject_mode, 1123d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt MEASURE_TYPE_BEACON, NULL, 0) < 0) { 1124d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); 1125d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt ret = -1; 1126d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 1127293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtout: 1128293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_clear_beacon_rep_data(wpa_s); 1129293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return ret; 1130293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1131293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1132293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1133293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic int 1134293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtwpas_rrm_handle_msr_req_element( 1135293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_supplicant *wpa_s, 1136293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct rrm_measurement_request_element *req, 1137293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf **buf) 1138293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1139293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int duration_mandatory; 1140293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1141293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "Measurement request type %d token %d", 1142293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->type, req->token); 1143293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1144293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) { 1145293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Enable bit is not supported for now */ 1146293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore"); 1147293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 1148293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1149293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1150293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) && 1151293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->type > MEASURE_TYPE_RPI_HIST) { 1152293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Parallel measurements are not supported for now */ 1153293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1154293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Parallel measurements are not supported, reject"); 1155293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto reject; 1156293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1157293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1158293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt duration_mandatory = 1159293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt !!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY); 1160293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1161293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt switch (req->type) { 1162293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case MEASURE_TYPE_LCI: 1163293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return wpas_rrm_build_lci_report(wpa_s, req, buf); 1164293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt case MEASURE_TYPE_BEACON: 1165293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (duration_mandatory && 1166293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt !(wpa_s->drv_rrm_flags & 1167293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL)) { 1168293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1169293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Driver does not support dwell time configuration - reject beacon report with mandatory duration"); 1170293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto reject; 1171293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1172293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return wpas_rm_handle_beacon_req(wpa_s, req->token, 1173293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt duration_mandatory, 1174293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (const void *) req->variable, 1175293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->len - 3, buf); 1176293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt default: 1177293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1178293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Unsupported radio measurement type %u", 1179293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->type); 1180293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 1181293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1182293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1183293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtreject: 1184d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) && 1185d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt wpas_rrm_report_elem(buf, req->token, 1186293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE, 1187293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->type, NULL, 0) < 0) { 1188293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Failed to add report element"); 1189293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return -1; 1190293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1191293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1192293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 1193293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1194293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1195293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1196293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic struct wpabuf * 1197293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtwpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos, 1198293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t len) 1199293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1200293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *buf = NULL; 1201293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1202293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt while (len) { 1203293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct rrm_measurement_request_element *req; 1204293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int res; 1205293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1206293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < 2) { 1207293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Truncated element"); 1208293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1209293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1210293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1211293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req = (const struct rrm_measurement_request_element *) pos; 1212293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->eid != WLAN_EID_MEASURE_REQUEST) { 1213293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1214293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Expected Measurement Request element, but EID is %u", 1215293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req->eid); 1216293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1217293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1218293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1219293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->len < 3) { 1220293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Element length too short"); 1221293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1222293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1223293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1224293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (req->len > len - 2) { 1225293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: Element length too long"); 1226293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1227293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1228293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1229293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf); 1230293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (res < 0) 1231293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1232293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1233293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt pos += req->len + 2; 1234293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt len -= req->len + 2; 1235293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1236293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1237293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return buf; 1238293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1239293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtout: 1240293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 1241293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return NULL; 1242293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1243293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1244293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1245293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtvoid wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, 1246d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt const u8 *src, const u8 *dst, 1247293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *frame, size_t len) 1248293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1249293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *report; 1250293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1251293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED) { 1252293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1253293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignoring radio measurement request: Not associated"); 1254293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1255293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1256293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1257293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->rrm.rrm_used) { 1258293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1259293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignoring radio measurement request: Not RRM network"); 1260293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1261293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1262293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1263293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < 3) { 1264293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1265293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignoring too short radio measurement request"); 1266293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1267293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1268293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1269293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->rrm.token = *frame; 1270d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN); 1271293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1272293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* Number of repetitions is not supported */ 1273293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1274293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3); 1275293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!report) 1276293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1277293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1278293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_send_msr_report(wpa_s, report); 1279293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(report); 1280293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1281293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1282293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1283293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtvoid wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, 1284293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *src, 1285293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const u8 *frame, size_t len, 1286293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt int rssi) 1287293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1288293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *buf; 1289293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt const struct rrm_link_measurement_request *req; 1290293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct rrm_link_measurement_report report; 1291293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1292293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_s->wpa_state != WPA_COMPLETED) { 1293293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1294293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignoring link measurement request. Not associated"); 1295293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1296293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1297293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1298293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->rrm.rrm_used) { 1299293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1300293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignoring link measurement request. Not RRM network"); 1301293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1302293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1303293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1304293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { 1305293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1306293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Measurement report failed. TX power insertion not supported"); 1307293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1308293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1309293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1310293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt req = (const struct rrm_link_measurement_request *) frame; 1311293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (len < sizeof(*req)) { 1312293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_INFO, 1313293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Link measurement report failed. Request too short"); 1314293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1315293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1316293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1317293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memset(&report, 0, sizeof(report)); 1318092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart report.dialog_token = req->dialog_token; 1319293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report.tpc.eid = WLAN_EID_TPC_REPORT; 1320293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report.tpc.len = 2; 1321092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart /* Note: The driver is expected to update report.tpc.tx_power and 1322092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * report.tpc.link_margin subfields when sending out this frame. 1323092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * Similarly, the driver would need to update report.rx_ant_id and 1324092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart * report.tx_ant_id subfields. */ 1325293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report.rsni = 255; /* 255 indicates that RSNI is not available */ 1326293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt report.rcpi = rssi_to_rcpi(rssi); 1327293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1328293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* action_category + action_code */ 1329293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt buf = wpabuf_alloc(2 + sizeof(report)); 1330293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (buf == NULL) { 1331293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_ERROR, 1332293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Link measurement report failed. Buffer allocation failed"); 1333293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return; 1334293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1335293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1336293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); 1337293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT); 1338293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_put_data(buf, &report, sizeof(report)); 1339092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf); 1340293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1341293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src, 1342293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->own_addr, wpa_s->bssid, 1343293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_head(buf), wpabuf_len(buf), 0)) { 1344293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_ERROR, 1345293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Link measurement report failed. Send action failed"); 1346293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1347293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 1348293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1349293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1350293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1351293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtint wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, 1352293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_scan_results *scan_res, 1353293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct scan_info *info) 1354293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1355293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt size_t i = 0; 1356293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpabuf *buf = NULL; 1357293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1358293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->beacon_rep_data.token) 1359293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 0; 1360293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1361293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!wpa_s->current_bss) 1362293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1363293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1364293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* If the measurement was aborted, don't report partial results */ 1365293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (info->aborted) 1366293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1367293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1368293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, "RRM: TSF BSSID: " MACSTR " current BSS: " MACSTR, 1369293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(info->scan_start_tsf_bssid), 1370293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(wpa_s->current_bss->bssid)); 1371293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && 1372293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcmp(info->scan_start_tsf_bssid, wpa_s->current_bss->bssid, 1373293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ETH_ALEN) != 0) { 1374293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1375293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignore scan results due to mismatching TSF BSSID"); 1376293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1377293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1378293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1379293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt for (i = 0; i < scan_res->num; i++) { 1380293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct wpa_bss *bss = 1381293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_bss_get_bssid(wpa_s, scan_res->res[i]->bssid); 1382293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1383293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!bss) 1384293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt continue; 1385293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1386293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if ((wpa_s->drv_rrm_flags & 1387293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && 1388293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memcmp(scan_res->res[i]->tsf_bssid, 1389293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_s->current_bss->bssid, ETH_ALEN) != 0) { 1390293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1391293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignore scan result for " MACSTR 1392293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt " due to mismatching TSF BSSID" MACSTR, 1393293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(scan_res->res[i]->bssid), 1394293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(scan_res->res[i]->tsf_bssid)); 1395293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt continue; 1396293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1397293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1398d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt /* 1399d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * Don't report results that were not received during the 1400d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt * current measurement. 1401d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt */ 1402293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!(wpa_s->drv_rrm_flags & 1403293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) { 1404293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct os_reltime update_time, diff; 1405293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1406293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt /* For now, allow 8 ms older results due to some 1407293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * unknown issue with cfg80211 BSS table updates during 1408293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * a scan with the current BSS. 1409293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * TODO: Fix this more properly to avoid having to have 1410293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt * this type of hacks in place. */ 1411293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt calculate_update_time(&scan_res->fetch_time, 1412293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt scan_res->res[i]->age, 1413293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt &update_time); 1414293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_reltime_sub(&wpa_s->beacon_rep_scan, 1415293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt &update_time, &diff); 1416293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (os_reltime_before(&update_time, 1417293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt &wpa_s->beacon_rep_scan) && 1418293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (diff.sec || diff.usec >= 8000)) { 1419293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_printf(MSG_DEBUG, 1420293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt "RRM: Ignore scan result for " MACSTR 1421293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt " due to old update (age(ms) %u, calculated age %u.%06u seconds)", 1422293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt MAC2STR(scan_res->res[i]->bssid), 1423293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt scan_res->res[i]->age, 1424293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (unsigned int) diff.sec, 1425293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt (unsigned int) diff.usec); 1426293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt continue; 1427293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1428d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } else if (info->scan_start_tsf > 1429d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt scan_res->res[i]->parent_tsf) { 1430293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt continue; 1431d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt } 1432293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1433293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf, 1434293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt scan_res->res[i]->parent_tsf) < 0) 1435293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt break; 1436293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt } 1437293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1438293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf)) 1439293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt goto out; 1440293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1441293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf); 1442293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1443293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_rrm_send_msr_report(wpa_s, buf); 1444293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpabuf_free(buf); 1445293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1446293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtout: 1447293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt wpas_clear_beacon_rep_data(wpa_s); 1448293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt return 1; 1449293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1450293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1451293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1452293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtvoid wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s) 1453293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{ 1454293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt struct beacon_rep_data *data = &wpa_s->beacon_rep_data; 1455293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 1456293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL); 1457293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt bitfield_free(data->eids); 1458293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_free(data->scan_params.freqs); 1459293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt os_memset(data, 0, sizeof(*data)); 1460293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt} 1461