blob: faa97e0b1e6ae6d46e61d83e7a1bf9768265e03e [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant - Scanning
Hai Shalom021b0b52019-04-10 11:17:58 -07003 * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "common/ieee802_11_defs.h"
Dmitry Shmidt3a787e62013-01-17 10:32:35 -080014#include "common/wpa_ctrl.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070015#include "config.h"
16#include "wpa_supplicant_i.h"
17#include "driver_i.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018#include "wps_supplicant.h"
19#include "p2p_supplicant.h"
20#include "p2p/p2p.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070021#include "hs20_supplicant.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include "notify.h"
23#include "bss.h"
24#include "scan.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080025#include "mesh.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026
27
28static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
29{
30 struct wpa_ssid *ssid;
31 union wpa_event_data data;
32
33 ssid = wpa_supplicant_get_ssid(wpa_s);
34 if (ssid == NULL)
35 return;
36
37 if (wpa_s->current_ssid == NULL) {
38 wpa_s->current_ssid = ssid;
Dmitry Shmidt849734c2016-05-27 09:59:01 -070039 wpas_notify_network_changed(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070040 }
41 wpa_supplicant_initiate_eapol(wpa_s);
42 wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
43 "network - generating associated event");
44 os_memset(&data, 0, sizeof(data));
45 wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
46}
47
48
49#ifdef CONFIG_WPS
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080050static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070051 enum wps_request_type *req_type)
52{
53 struct wpa_ssid *ssid;
54 int wps = 0;
55
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080056 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070057 if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
58 continue;
59
60 wps = 1;
61 *req_type = wpas_wps_get_req_type(ssid);
Dmitry Shmidt849734c2016-05-27 09:59:01 -070062 if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1"))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070063 return 2;
64 }
65
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080066#ifdef CONFIG_P2P
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080067 if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
68 !wpa_s->conf->p2p_disabled) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080069 wpa_s->wps->dev.p2p = 1;
70 if (!wps) {
71 wps = 1;
72 *req_type = WPS_REQ_ENROLLEE_INFO;
73 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080074 }
75#endif /* CONFIG_P2P */
76
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070077 return wps;
78}
79#endif /* CONFIG_WPS */
80
81
Hai Shalomc3565922019-10-28 11:58:20 -070082static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
83 const u8 *mac_addr)
84{
85 u8 *tmp;
86
87 if (params->mac_addr) {
88 params->mac_addr_mask = NULL;
89 os_free(params->mac_addr);
90 params->mac_addr = NULL;
91 }
92
93 params->mac_addr_rand = 1;
94
95 if (!mac_addr)
96 return 0;
97
98 tmp = os_malloc(2 * ETH_ALEN);
99 if (!tmp)
100 return -1;
101
102 os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
103 params->mac_addr = tmp;
104 params->mac_addr_mask = tmp + ETH_ALEN;
105 return 0;
106}
107
108
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800109/**
110 * wpa_supplicant_enabled_networks - Check whether there are enabled networks
111 * @wpa_s: Pointer to wpa_supplicant data
112 * Returns: 0 if no networks are enabled, >0 if networks are enabled
113 *
114 * This function is used to figure out whether any networks (or Interworking
115 * with enabled credentials and auto_interworking) are present in the current
116 * configuration.
117 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700118int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700119{
Dmitry Shmidt04949592012-07-19 12:16:46 -0700120 struct wpa_ssid *ssid = wpa_s->conf->ssid;
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700121 int count = 0, disabled = 0;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800122
123 if (wpa_s->p2p_mgmt)
124 return 0; /* no normal network profiles on p2p_mgmt interface */
125
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700126 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700127 if (!wpas_network_disabled(wpa_s, ssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700128 count++;
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700129 else
130 disabled++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700131 ssid = ssid->next;
132 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700133 if (wpa_s->conf->cred && wpa_s->conf->interworking &&
134 wpa_s->conf->auto_interworking)
135 count++;
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700136 if (count == 0 && disabled > 0) {
137 wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled "
138 "networks)", disabled);
139 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700140 return count;
141}
142
143
144static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
145 struct wpa_ssid *ssid)
146{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700147 int min_temp_disabled = 0;
148
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700149 while (ssid) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700150 if (!wpas_network_disabled(wpa_s, ssid)) {
151 int temp_disabled = wpas_temp_disabled(wpa_s, ssid);
152
153 if (temp_disabled <= 0)
154 break;
155
156 if (!min_temp_disabled ||
157 temp_disabled < min_temp_disabled)
158 min_temp_disabled = temp_disabled;
159 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700160 ssid = ssid->next;
161 }
162
163 /* ap_scan=2 mode - try to associate with each SSID. */
164 if (ssid == NULL) {
165 wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached "
166 "end of scan list - go back to beginning");
167 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700168 wpa_supplicant_req_scan(wpa_s, min_temp_disabled, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169 return;
170 }
171 if (ssid->next) {
172 /* Continue from the next SSID on the next attempt. */
173 wpa_s->prev_scan_ssid = ssid;
174 } else {
175 /* Start from the beginning of the SSID list. */
176 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
177 }
178 wpa_supplicant_associate(wpa_s, NULL, ssid);
179}
180
181
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800182static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700183{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800184 struct wpa_supplicant *wpa_s = work->wpa_s;
185 struct wpa_driver_scan_params *params = work->ctx;
186 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700187
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800188 if (deinit) {
Dmitry Shmidtbd14a572014-02-18 10:33:49 -0800189 if (!work->started) {
190 wpa_scan_free_params(params);
191 return;
192 }
193 wpa_supplicant_notify_scanning(wpa_s, 0);
194 wpas_notify_scan_done(wpa_s, 0);
195 wpa_s->scan_work = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700196 return;
197 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700198
Hai Shalomc3565922019-10-28 11:58:20 -0700199 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
200 wpa_s->wpa_state <= WPA_SCANNING)
201 wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
202
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700203 if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
204 wpa_msg(wpa_s, MSG_INFO,
205 "Failed to assign random MAC address for a scan");
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700206 wpa_scan_free_params(params);
207 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
Dmitry Shmidt661b4f72014-09-29 14:58:27 -0700208 radio_work_done(work);
209 return;
210 }
211
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800212 wpa_supplicant_notify_scanning(wpa_s, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700213
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800214 if (wpa_s->clear_driver_scan_cache) {
215 wpa_printf(MSG_DEBUG,
216 "Request driver to clear scan cache due to local BSS flush");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800217 params->only_new_results = 1;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800218 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800219 ret = wpa_drv_scan(wpa_s, params);
Dmitry Shmidtabb90a32016-12-05 15:34:39 -0800220 /*
221 * Store the obtained vendor scan cookie (if any) in wpa_s context.
222 * The current design is to allow only one scan request on each
223 * interface, hence having this scan cookie stored in wpa_s context is
224 * fine for now.
225 *
226 * Revisit this logic if concurrent scan operations per interface
227 * is supported.
228 */
229 if (ret == 0)
230 wpa_s->curr_scan_cookie = params->scan_cookie;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800231 wpa_scan_free_params(params);
232 work->ctx = NULL;
233 if (ret) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700234 int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
235 !wpa_s->beacon_rep_data.token;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800236
237 if (wpa_s->disconnected)
238 retry = 0;
239
Hai Shalom899fcc72020-10-19 14:38:18 -0700240 /* do not retry if operation is not supported */
241 if (ret == -EOPNOTSUPP)
242 retry = 0;
243
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800244 wpa_supplicant_notify_scanning(wpa_s, 0);
245 wpas_notify_scan_done(wpa_s, 0);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800246 if (wpa_s->wpa_state == WPA_SCANNING)
247 wpa_supplicant_set_state(wpa_s,
248 wpa_s->scan_prev_wpa_state);
249 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d%s",
250 ret, retry ? " retry=1" : "");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800251 radio_work_done(work);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800252
253 if (retry) {
254 /* Restore scan_req since we will try to scan again */
255 wpa_s->scan_req = wpa_s->last_scan_req;
256 wpa_supplicant_req_scan(wpa_s, 1, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700257 } else if (wpa_s->scan_res_handler) {
258 /* Clear the scan_res_handler */
259 wpa_s->scan_res_handler = NULL;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800260 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700261
262 if (wpa_s->beacon_rep_data.token)
263 wpas_rrm_refuse_request(wpa_s);
264
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700265 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700266 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800267
268 os_get_reltime(&wpa_s->scan_trigger_time);
269 wpa_s->scan_runs++;
270 wpa_s->normal_scans++;
271 wpa_s->own_scan_requested = 1;
272 wpa_s->clear_driver_scan_cache = 0;
273 wpa_s->scan_work = work;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700274}
275
276
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800277/**
278 * wpa_supplicant_trigger_scan - Request driver to start a scan
279 * @wpa_s: Pointer to wpa_supplicant data
280 * @params: Scan parameters
281 * Returns: 0 on success, -1 on failure
282 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700283int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
284 struct wpa_driver_scan_params *params)
285{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800286 struct wpa_driver_scan_params *ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700287
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800288 if (wpa_s->scan_work) {
289 wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
290 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800291 }
292
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800293 ctx = wpa_scan_clone_params(params);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700294 if (!ctx ||
295 radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800296 {
297 wpa_scan_free_params(ctx);
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700298 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800299 return -1;
300 }
301
302 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800303}
304
305
306static void
307wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
308{
309 struct wpa_supplicant *wpa_s = eloop_ctx;
310
311 wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan");
312
313 if (wpa_supplicant_req_sched_scan(wpa_s))
314 wpa_supplicant_req_scan(wpa_s, 0, 0);
315}
316
317
318static void
319wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
320{
321 struct wpa_supplicant *wpa_s = eloop_ctx;
322
323 wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it");
324
325 wpa_s->sched_scan_timed_out = 1;
326 wpa_supplicant_cancel_sched_scan(wpa_s);
327}
328
329
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700330static int
331wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
332 struct wpa_driver_scan_params *params)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800333{
334 int ret;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700335
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800336 wpa_supplicant_notify_scanning(wpa_s, 1);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800337 ret = wpa_drv_sched_scan(wpa_s, params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800338 if (ret)
339 wpa_supplicant_notify_scanning(wpa_s, 0);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800340 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800341 wpa_s->sched_scanning = 1;
342
343 return ret;
344}
345
346
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700347static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800348{
349 int ret;
350
351 ret = wpa_drv_stop_sched_scan(wpa_s);
352 if (ret) {
353 wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!");
354 /* TODO: what to do if stopping fails? */
355 return -1;
356 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700357
358 return ret;
359}
360
361
362static struct wpa_driver_scan_filter *
363wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
364{
365 struct wpa_driver_scan_filter *ssids;
366 struct wpa_ssid *ssid;
367 size_t count;
368
369 *num_ssids = 0;
370 if (!conf->filter_ssids)
371 return NULL;
372
373 for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) {
374 if (ssid->ssid && ssid->ssid_len)
375 count++;
376 }
377 if (count == 0)
378 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800379 ssids = os_calloc(count, sizeof(struct wpa_driver_scan_filter));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700380 if (ssids == NULL)
381 return NULL;
382
383 for (ssid = conf->ssid; ssid; ssid = ssid->next) {
384 if (!ssid->ssid || !ssid->ssid_len)
385 continue;
386 os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len);
387 ssids[*num_ssids].ssid_len = ssid->ssid_len;
388 (*num_ssids)++;
389 }
390
391 return ssids;
392}
393
394
Hai Shaloma20dcd72022-02-04 13:43:00 -0800395#ifdef CONFIG_P2P
396static bool is_6ghz_supported(struct wpa_supplicant *wpa_s)
397{
398 struct hostapd_channel_data *chnl;
399 int i, j;
400
401 for (i = 0; i < wpa_s->hw.num_modes; i++) {
402 if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) {
403 chnl = wpa_s->hw.modes[i].channels;
404 for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) {
405 if (chnl[j].flag & HOSTAPD_CHAN_DISABLED)
406 continue;
407 if (is_6ghz_freq(chnl[j].freq))
408 return true;
409 }
410 }
411 }
412
413 return false;
414}
415#endif /* CONFIG_P2P */
416
417
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800418static void wpa_supplicant_optimize_freqs(
419 struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
420{
421#ifdef CONFIG_P2P
422 if (params->freqs == NULL && wpa_s->p2p_in_provisioning &&
423 wpa_s->go_params) {
424 /* Optimize provisioning state scan based on GO information */
425 if (wpa_s->p2p_in_provisioning < 5 &&
426 wpa_s->go_params->freq > 0) {
427 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
428 "preferred frequency %d MHz",
429 wpa_s->go_params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800430 params->freqs = os_calloc(2, sizeof(int));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800431 if (params->freqs)
432 params->freqs[0] = wpa_s->go_params->freq;
433 } else if (wpa_s->p2p_in_provisioning < 8 &&
434 wpa_s->go_params->freq_list[0]) {
435 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
436 "channels");
437 int_array_concat(&params->freqs,
438 wpa_s->go_params->freq_list);
439 if (params->freqs)
440 int_array_sort_unique(params->freqs);
441 }
442 wpa_s->p2p_in_provisioning++;
443 }
Dmitry Shmidt15907092014-03-25 10:42:57 -0700444
445 if (params->freqs == NULL && wpa_s->p2p_in_invitation) {
446 /*
Matthew Wangdcf19452022-11-07 20:42:52 -0800447 * Perform a single-channel scan if the GO has already been
448 * discovered on another non-P2P interface. Note that a scan
449 * initiated by a P2P interface (e.g. the device interface)
450 * should already have sufficient IEs and scan results will be
451 * fetched on interface creation in that case.
452 */
453 if (wpa_s->p2p_in_invitation == 1 && wpa_s->current_ssid) {
454 struct wpa_supplicant *ifs;
455 struct wpa_bss *bss = NULL;
456 struct wpa_ssid *ssid = wpa_s->current_ssid;
457 u8 *bssid = ssid->bssid_set ? ssid->bssid : NULL;
458 dl_list_for_each(ifs, &wpa_s->radio->ifaces,
459 struct wpa_supplicant, radio_list) {
460 bss = wpa_bss_get(ifs, bssid, ssid->ssid,
461 ssid->ssid_len);
462 if (bss)
463 break;
464 }
465 if (bss && !disabled_freq(wpa_s, bss->freq)) {
466 params->freqs = os_calloc(2, sizeof(int));
467 if (params->freqs)
468 params->freqs[0] = bss->freq;
469 }
470 }
471 /*
Dmitry Shmidt15907092014-03-25 10:42:57 -0700472 * Optimize scan based on GO information during persistent
473 * group reinvocation
474 */
Matthew Wangdcf19452022-11-07 20:42:52 -0800475 if (params->freqs == NULL && wpa_s->p2p_in_invitation < 5 &&
Dmitry Shmidt15907092014-03-25 10:42:57 -0700476 wpa_s->p2p_invite_go_freq > 0) {
Matthew Wang36173112022-11-07 21:48:44 -0800477 if (wpa_s->p2p_invite_go_freq == 2 ||
478 wpa_s->p2p_invite_go_freq == 5) {
479 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred band %d GHz during invitation",
480 wpa_s->p2p_invite_go_freq);
481 enum hostapd_hw_mode mode;
482 if (wpa_s->hw.modes == NULL)
483 return;
484 mode = wpa_s->p2p_invite_go_freq == 5 ?
485 HOSTAPD_MODE_IEEE80211A :
486 HOSTAPD_MODE_IEEE80211G;
487 if (wpa_s->p2p_in_invitation <= 2)
488 wpa_add_scan_freqs_list(wpa_s, mode,
489 params, false,
490 true);
491 if (params->freqs == NULL ||
492 (params->freqs && params->freqs[0] == 0))
493 wpa_add_scan_freqs_list(wpa_s, mode,
494 params, false,
495 false);
496 } else {
497 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
498 wpa_s->p2p_invite_go_freq);
499 params->freqs = os_calloc(2, sizeof(int));
500 if (params->freqs)
501 params->freqs[0] =
502 wpa_s->p2p_invite_go_freq;
503 }
Dmitry Shmidt15907092014-03-25 10:42:57 -0700504 }
505 wpa_s->p2p_in_invitation++;
506 if (wpa_s->p2p_in_invitation > 20) {
507 /*
508 * This should not really happen since the variable is
509 * cleared on group removal, but if it does happen, make
510 * sure we do not get stuck in special invitation scan
511 * mode.
512 */
513 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation");
514 wpa_s->p2p_in_invitation = 0;
Matthew Wang06b42472022-11-10 06:56:31 +0000515 wpa_s->p2p_retry_limit = 0;
Dmitry Shmidt15907092014-03-25 10:42:57 -0700516 }
517 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800518#endif /* CONFIG_P2P */
519
520#ifdef CONFIG_WPS
521 if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
522 /*
523 * Optimize post-provisioning scan based on channel used
524 * during provisioning.
525 */
526 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
527 "that was used during provisioning", wpa_s->wps_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800528 params->freqs = os_calloc(2, sizeof(int));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800529 if (params->freqs)
530 params->freqs[0] = wpa_s->wps_freq;
531 wpa_s->after_wps--;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800532 } else if (wpa_s->after_wps)
533 wpa_s->after_wps--;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800534
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800535 if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
536 {
537 /* Optimize provisioning scan based on already known channel */
538 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
539 wpa_s->wps_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800540 params->freqs = os_calloc(2, sizeof(int));
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800541 if (params->freqs)
542 params->freqs[0] = wpa_s->wps_freq;
543 wpa_s->known_wps_freq = 0; /* only do this once */
544 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800545#endif /* CONFIG_WPS */
546}
547
548
549#ifdef CONFIG_INTERWORKING
550static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
551 struct wpabuf *buf)
552{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800553 wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
554 wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
555 1 + ETH_ALEN);
556 wpabuf_put_u8(buf, wpa_s->conf->access_network_type);
557 /* No Venue Info */
558 if (!is_zero_ether_addr(wpa_s->conf->hessid))
559 wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN);
560}
561#endif /* CONFIG_INTERWORKING */
562
563
Hai Shalomce48b4a2018-09-05 11:41:35 -0700564#ifdef CONFIG_MBO
565static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s,
566 struct wpabuf **ie)
567{
568 if (wpabuf_resize(ie, 5)) {
569 wpa_printf(MSG_DEBUG,
570 "Failed to allocate space for FILS Request Parameters element");
571 return;
572 }
573
574 /* FILS Request Parameters element */
575 wpabuf_put_u8(*ie, WLAN_EID_EXTENSION);
576 wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */
577 wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS);
578 /* Parameter control bitmap */
579 wpabuf_put_u8(*ie, 0);
580 /* Max Channel Time field - contains the value of MaxChannelTime
581 * parameter of the MLME-SCAN.request primitive represented in units of
582 * TUs, as an unsigned integer. A Max Channel Time field value of 255
583 * is used to indicate any duration of more than 254 TUs, or an
584 * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178)
585 */
586 wpabuf_put_u8(*ie, 255);
587}
588#endif /* CONFIG_MBO */
589
590
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700591void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
592{
593 struct wpabuf *default_ies = NULL;
594 u8 ext_capab[18];
Hai Shalom60840252021-02-19 19:02:11 -0800595 int ext_capab_len, frame_id;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700596 enum wpa_driver_if_type type = WPA_IF_STATION;
597
598#ifdef CONFIG_P2P
599 if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
600 type = WPA_IF_P2P_CLIENT;
601#endif /* CONFIG_P2P */
602
603 wpa_drv_get_ext_capa(wpa_s, type);
604
605 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
606 sizeof(ext_capab));
607 if (ext_capab_len > 0 &&
608 wpabuf_resize(&default_ies, ext_capab_len) == 0)
609 wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
610
611#ifdef CONFIG_MBO
Hai Shalomce48b4a2018-09-05 11:41:35 -0700612 if (wpa_s->enable_oce & OCE_STA)
613 wpas_fils_req_param_add_max_channel(wpa_s, &default_ies);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700614 /* Send MBO and OCE capabilities */
615 if (wpabuf_resize(&default_ies, 12) == 0)
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700616 wpas_mbo_scan_ie(wpa_s, default_ies);
617#endif /* CONFIG_MBO */
618
Hai Shalom60840252021-02-19 19:02:11 -0800619 if (type == WPA_IF_P2P_CLIENT)
620 frame_id = VENDOR_ELEM_PROBE_REQ_P2P;
621 else
622 frame_id = VENDOR_ELEM_PROBE_REQ;
623
624 if (wpa_s->vendor_elem[frame_id]) {
625 size_t len;
626
627 len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
628 if (len > 0 && wpabuf_resize(&default_ies, len) == 0)
629 wpabuf_put_buf(default_ies,
630 wpa_s->vendor_elem[frame_id]);
631 }
632
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700633 if (default_ies)
634 wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
635 wpabuf_len(default_ies));
636 wpabuf_free(default_ies);
637}
638
639
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700640static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800641{
642 struct wpabuf *extra_ie = NULL;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700643 u8 ext_capab[18];
644 int ext_capab_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800645#ifdef CONFIG_WPS
646 int wps = 0;
647 enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
648#endif /* CONFIG_WPS */
649
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700650#ifdef CONFIG_P2P
651 if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
652 wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
653 else
654#endif /* CONFIG_P2P */
655 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
656
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700657 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
658 sizeof(ext_capab));
659 if (ext_capab_len > 0 &&
660 wpabuf_resize(&extra_ie, ext_capab_len) == 0)
661 wpabuf_put_data(extra_ie, ext_capab, ext_capab_len);
662
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800663#ifdef CONFIG_INTERWORKING
664 if (wpa_s->conf->interworking &&
665 wpabuf_resize(&extra_ie, 100) == 0)
666 wpas_add_interworking_elements(wpa_s, extra_ie);
667#endif /* CONFIG_INTERWORKING */
668
Hai Shalomce48b4a2018-09-05 11:41:35 -0700669#ifdef CONFIG_MBO
670 if (wpa_s->enable_oce & OCE_STA)
671 wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie);
672#endif /* CONFIG_MBO */
673
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800674#ifdef CONFIG_WPS
675 wps = wpas_wps_in_use(wpa_s, &req_type);
676
677 if (wps) {
678 struct wpabuf *wps_ie;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700679 wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
680 DEV_PW_DEFAULT,
681 &wpa_s->wps->dev,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800682 wpa_s->wps->uuid, req_type,
683 0, NULL);
684 if (wps_ie) {
685 if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
686 wpabuf_put_buf(extra_ie, wps_ie);
687 wpabuf_free(wps_ie);
688 }
689 }
690
691#ifdef CONFIG_P2P
692 if (wps) {
693 size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
694 if (wpabuf_resize(&extra_ie, ielen) == 0)
695 wpas_p2p_scan_ie(wpa_s, extra_ie);
696 }
697#endif /* CONFIG_P2P */
698
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800699 wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
700
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800701#endif /* CONFIG_WPS */
702
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700703#ifdef CONFIG_HS20
Hai Shalom74f70d42019-02-11 14:42:39 -0800704 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0)
705 wpas_hs20_add_indication(extra_ie, -1, 0);
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700706#endif /* CONFIG_HS20 */
707
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800708#ifdef CONFIG_FST
709 if (wpa_s->fst_ies &&
710 wpabuf_resize(&extra_ie, wpabuf_len(wpa_s->fst_ies)) == 0)
711 wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
712#endif /* CONFIG_FST */
713
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800714#ifdef CONFIG_MBO
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700715 /* Send MBO and OCE capabilities */
716 if (wpabuf_resize(&extra_ie, 12) == 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800717 wpas_mbo_scan_ie(wpa_s, extra_ie);
718#endif /* CONFIG_MBO */
719
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700720 if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
721 struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
722
723 if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
724 wpabuf_put_buf(extra_ie, buf);
725 }
726
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800727 return extra_ie;
728}
729
730
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800731#ifdef CONFIG_P2P
732
733/*
734 * Check whether there are any enabled networks or credentials that could be
735 * used for a non-P2P connection.
736 */
737static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
738{
739 struct wpa_ssid *ssid;
740
741 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
742 if (wpas_network_disabled(wpa_s, ssid))
743 continue;
744 if (!ssid->p2p_group)
745 return 1;
746 }
747
748 if (wpa_s->conf->cred && wpa_s->conf->interworking &&
749 wpa_s->conf->auto_interworking)
750 return 1;
751
752 return 0;
753}
754
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700755#endif /* CONFIG_P2P */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800756
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800757
Hai Shalom60840252021-02-19 19:02:11 -0800758int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
759 enum hostapd_hw_mode band,
Matthew Wang36173112022-11-07 21:48:44 -0800760 struct wpa_driver_scan_params *params, bool is_6ghz,
761 bool exclude_radar)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700762{
763 /* Include only supported channels for the specified band */
764 struct hostapd_hw_modes *mode;
Hai Shalom60840252021-02-19 19:02:11 -0800765 int num_chans = 0;
766 int *freqs, i;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700767
Hai Shalomfdcde762020-04-02 11:19:20 -0700768 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
Hai Shalom60840252021-02-19 19:02:11 -0800769 if (!mode)
770 return -1;
771
772 if (params->freqs) {
773 while (params->freqs[num_chans])
774 num_chans++;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700775 }
776
Hai Shalom60840252021-02-19 19:02:11 -0800777 freqs = os_realloc(params->freqs,
778 (num_chans + mode->num_channels + 1) * sizeof(int));
779 if (!freqs)
780 return -1;
781
782 params->freqs = freqs;
783 for (i = 0; i < mode->num_channels; i++) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700784 if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
785 continue;
Matthew Wang36173112022-11-07 21:48:44 -0800786 if (exclude_radar && (mode->channels[i].flag & HOSTAPD_CHAN_RADAR))
787 continue;
Hai Shalom60840252021-02-19 19:02:11 -0800788 params->freqs[num_chans++] = mode->channels[i].freq;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700789 }
Hai Shalom60840252021-02-19 19:02:11 -0800790 params->freqs[num_chans] = 0;
791
792 return 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700793}
794
795
796static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
797 struct wpa_driver_scan_params *params)
798{
799 if (wpa_s->hw.modes == NULL)
800 return; /* unknown what channels the driver supports */
801 if (params->freqs)
802 return; /* already using a limited channel set */
Hai Shalom60840252021-02-19 19:02:11 -0800803
804 if (wpa_s->setband_mask & WPA_SETBAND_5G)
805 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
Matthew Wang36173112022-11-07 21:48:44 -0800806 false, false);
Hai Shalom60840252021-02-19 19:02:11 -0800807 if (wpa_s->setband_mask & WPA_SETBAND_2G)
808 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
Matthew Wang36173112022-11-07 21:48:44 -0800809 false, false);
Hai Shalom60840252021-02-19 19:02:11 -0800810 if (wpa_s->setband_mask & WPA_SETBAND_6G)
811 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
Matthew Wang36173112022-11-07 21:48:44 -0800812 true, false);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700813}
814
815
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800816static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s,
817 struct wpa_driver_scan_params *params,
818 size_t max_ssids, const u8 *ssid, size_t ssid_len)
819{
820 unsigned int j;
821
822 for (j = 0; j < params->num_ssids; j++) {
823 if (params->ssids[j].ssid_len == ssid_len &&
824 params->ssids[j].ssid &&
825 os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0)
826 return; /* already in the list */
827 }
828
829 if (params->num_ssids + 1 > max_ssids) {
830 wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request");
831 return;
832 }
833
834 wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
835 wpa_ssid_txt(ssid, ssid_len));
836
837 params->ssids[params->num_ssids].ssid = ssid;
838 params->ssids[params->num_ssids].ssid_len = ssid_len;
839 params->num_ssids++;
840}
841
842
843static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
844 struct wpa_driver_scan_params *params,
845 struct wpa_ssid *ssid, size_t max_ssids)
846{
847#ifdef CONFIG_OWE
848 struct wpa_bss *bss;
849
850 if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE))
851 return;
852
853 wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s",
854 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
855
856 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
857 const u8 *owe, *pos, *end;
858 const u8 *owe_ssid;
859 size_t owe_ssid_len;
860
861 if (bss->ssid_len != ssid->ssid_len ||
862 os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0)
863 continue;
864
865 owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
866 if (!owe || owe[1] < 4)
867 continue;
868
869 pos = owe + 6;
870 end = owe + 2 + owe[1];
871
872 /* Must include BSSID and ssid_len */
873 if (end - pos < ETH_ALEN + 1)
874 return;
875
876 /* Skip BSSID */
877 pos += ETH_ALEN;
878 owe_ssid_len = *pos++;
879 owe_ssid = pos;
880
881 if ((size_t) (end - pos) < owe_ssid_len ||
882 owe_ssid_len > SSID_MAX_LEN)
883 return;
884
885 wpa_printf(MSG_DEBUG,
886 "OWE: scan_ssids: transition mode OWE ssid=%s",
887 wpa_ssid_txt(owe_ssid, owe_ssid_len));
888
889 wpa_add_scan_ssid(wpa_s, params, max_ssids,
890 owe_ssid, owe_ssid_len);
891 return;
892 }
893#endif /* CONFIG_OWE */
894}
895
896
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700897static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
898 struct wpa_driver_scan_params *params,
899 size_t max_ssids)
900{
901 unsigned int i;
902 struct wpa_ssid *ssid;
903
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -0700904 /*
905 * For devices with max_ssids greater than 1, leave the last slot empty
906 * for adding the wildcard scan entry.
907 */
908 max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
909
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700910 for (i = 0; i < wpa_s->scan_id_count; i++) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700911 ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]);
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800912 if (!ssid)
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700913 continue;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800914 if (ssid->scan_ssid)
915 wpa_add_scan_ssid(wpa_s, params, max_ssids,
916 ssid->ssid, ssid->ssid_len);
917 /*
918 * Also add the SSID of the OWE BSS, to allow discovery of
919 * transition mode APs more quickly.
920 */
921 wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids);
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700922 }
923
924 wpa_s->scan_id_count = 0;
925}
926
927
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -0700928static int wpa_set_ssids_from_scan_req(struct wpa_supplicant *wpa_s,
929 struct wpa_driver_scan_params *params,
930 size_t max_ssids)
931{
932 unsigned int i;
933
934 if (wpa_s->ssids_from_scan_req == NULL ||
935 wpa_s->num_ssids_from_scan_req == 0)
936 return 0;
937
938 if (wpa_s->num_ssids_from_scan_req > max_ssids) {
939 wpa_s->num_ssids_from_scan_req = max_ssids;
940 wpa_printf(MSG_DEBUG, "Over max scan SSIDs from scan req: %u",
941 (unsigned int) max_ssids);
942 }
943
944 for (i = 0; i < wpa_s->num_ssids_from_scan_req; i++) {
945 params->ssids[i].ssid = wpa_s->ssids_from_scan_req[i].ssid;
946 params->ssids[i].ssid_len =
947 wpa_s->ssids_from_scan_req[i].ssid_len;
948 wpa_hexdump_ascii(MSG_DEBUG, "specific SSID",
949 params->ssids[i].ssid,
950 params->ssids[i].ssid_len);
951 }
952
953 params->num_ssids = wpa_s->num_ssids_from_scan_req;
954 wpa_s->num_ssids_from_scan_req = 0;
955 return 1;
956}
957
958
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700959static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
960{
961 struct wpa_supplicant *wpa_s = eloop_ctx;
962 struct wpa_ssid *ssid;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800963 int ret, p2p_in_prog;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700964 struct wpabuf *extra_ie = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700965 struct wpa_driver_scan_params params;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700966 struct wpa_driver_scan_params *scan_params;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700967 size_t max_ssids;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800968 int connect_without_scan = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700969
Dmitry Shmidt29333592017-01-09 12:27:11 -0800970 wpa_s->ignore_post_flush_scan_res = 0;
971
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700972 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
973 wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
974 return;
975 }
976
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800977 if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700978 wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700979 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
980 return;
981 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800982
Dmitry Shmidt5887a9d2012-09-14 10:47:43 -0700983 if (wpa_s->scanning) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800984 /*
985 * If we are already in scanning state, we shall reschedule the
986 * the incoming scan request.
987 */
988 wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
989 wpa_supplicant_req_scan(wpa_s, 1, 0);
Dmitry Shmidt5887a9d2012-09-14 10:47:43 -0700990 return;
991 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800992
Dmitry Shmidt04949592012-07-19 12:16:46 -0700993 if (!wpa_supplicant_enabled_networks(wpa_s) &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800994 wpa_s->scan_req == NORMAL_SCAN_REQ) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
996 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
997 return;
998 }
999
1000 if (wpa_s->conf->ap_scan != 0 &&
1001 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
1002 wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
1003 "overriding ap_scan configuration");
1004 wpa_s->conf->ap_scan = 0;
1005 wpas_notify_ap_scan_changed(wpa_s);
1006 }
1007
1008 if (wpa_s->conf->ap_scan == 0) {
1009 wpa_supplicant_gen_assoc_event(wpa_s);
1010 return;
1011 }
1012
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001013 ssid = NULL;
1014 if (wpa_s->scan_req != MANUAL_SCAN_REQ &&
1015 wpa_s->connect_without_scan) {
1016 connect_without_scan = 1;
1017 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1018 if (ssid == wpa_s->connect_without_scan)
1019 break;
1020 }
1021 }
1022
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001023 p2p_in_prog = wpas_p2p_in_progress(wpa_s);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001024 if (p2p_in_prog && p2p_in_prog != 2 &&
1025 (!ssid ||
1026 (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001027 wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
1028 wpa_supplicant_req_scan(wpa_s, 5, 0);
Dmitry Shmidt051af732013-10-22 13:52:46 -07001029 return;
1030 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07001031
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001032 /*
1033 * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
1034 * used for changing modes inside wpa_supplicant (roaming,
1035 * auto-reconnect, etc). Discarding the scan might hurt these processes.
1036 * The normal use case for PNO is to suspend the host immediately after
1037 * starting PNO, so the periodic 100 ms attempts to run the scan do not
1038 * normally happen in practice multiple times, i.e., this is simply
1039 * restarting scanning once the host is woken up and PNO stopped.
1040 */
1041 if (wpa_s->pno || wpa_s->pno_sched_pending) {
1042 wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
1043 wpa_supplicant_req_scan(wpa_s, 0, 100000);
1044 return;
1045 }
1046
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001047 if (wpa_s->conf->ap_scan == 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001048 max_ssids = 1;
1049 else {
1050 max_ssids = wpa_s->max_scan_ssids;
1051 if (max_ssids > WPAS_MAX_SCAN_SSIDS)
1052 max_ssids = WPAS_MAX_SCAN_SSIDS;
1053 }
1054
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001055 wpa_s->last_scan_req = wpa_s->scan_req;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001056 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001057
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001058 if (connect_without_scan) {
1059 wpa_s->connect_without_scan = NULL;
1060 if (ssid) {
1061 wpa_printf(MSG_DEBUG, "Start a pre-selected network "
1062 "without scan step");
1063 wpa_supplicant_associate(wpa_s, NULL, ssid);
1064 return;
1065 }
1066 }
1067
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001068 os_memset(&params, 0, sizeof(params));
1069
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001070 wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001071 if (wpa_s->wpa_state == WPA_DISCONNECTED ||
1072 wpa_s->wpa_state == WPA_INACTIVE)
1073 wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
1074
Dmitry Shmidt04949592012-07-19 12:16:46 -07001075 /*
1076 * If autoscan has set its own scanning parameters
1077 */
1078 if (wpa_s->autoscan_params != NULL) {
1079 scan_params = wpa_s->autoscan_params;
1080 goto scan;
1081 }
1082
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07001083 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
1084 wpa_set_ssids_from_scan_req(wpa_s, &params, max_ssids)) {
1085 wpa_printf(MSG_DEBUG, "Use specific SSIDs from SCAN command");
1086 goto ssid_list_set;
1087 }
1088
Dmitry Shmidt04949592012-07-19 12:16:46 -07001089#ifdef CONFIG_P2P
1090 if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001091 wpa_s->go_params && !wpa_s->conf->passive_scan) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001092 wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
1093 wpa_s->p2p_in_provisioning,
1094 wpa_s->show_group_started);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001095 params.ssids[0].ssid = wpa_s->go_params->ssid;
1096 params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
1097 params.num_ssids = 1;
1098 goto ssid_list_set;
1099 }
Dmitry Shmidt15907092014-03-25 10:42:57 -07001100
1101 if (wpa_s->p2p_in_invitation) {
1102 if (wpa_s->current_ssid) {
1103 wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation");
1104 params.ssids[0].ssid = wpa_s->current_ssid->ssid;
1105 params.ssids[0].ssid_len =
1106 wpa_s->current_ssid->ssid_len;
1107 params.num_ssids = 1;
1108 } else {
1109 wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation");
1110 }
1111 goto ssid_list_set;
1112 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001113#endif /* CONFIG_P2P */
1114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001115 /* Find the starting point from which to continue scanning */
1116 ssid = wpa_s->conf->ssid;
1117 if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
1118 while (ssid) {
1119 if (ssid == wpa_s->prev_scan_ssid) {
1120 ssid = ssid->next;
1121 break;
1122 }
1123 ssid = ssid->next;
1124 }
1125 }
1126
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001127 if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001128#ifdef CONFIG_AP
1129 !wpa_s->ap_iface &&
1130#endif /* CONFIG_AP */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001131 wpa_s->conf->ap_scan == 2) {
Jouni Malinen75ecf522011-06-27 15:19:46 -07001132 wpa_s->connect_without_scan = NULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001133 wpa_s->prev_scan_wildcard = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001134 wpa_supplicant_assoc_try(wpa_s, ssid);
1135 return;
1136 } else if (wpa_s->conf->ap_scan == 2) {
1137 /*
1138 * User-initiated scan request in ap_scan == 2; scan with
1139 * wildcard SSID.
1140 */
1141 ssid = NULL;
Dmitry Shmidt98660862014-03-11 17:26:21 -07001142 } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) {
1143 /*
1144 * Perform single-channel single-SSID scan for
1145 * reassociate-to-same-BSS operation.
1146 */
1147 /* Setup SSID */
1148 ssid = wpa_s->current_ssid;
1149 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
1150 ssid->ssid, ssid->ssid_len);
1151 params.ssids[0].ssid = ssid->ssid;
1152 params.ssids[0].ssid_len = ssid->ssid_len;
1153 params.num_ssids = 1;
1154
1155 /*
1156 * Allocate memory for frequency array, allocate one extra
1157 * slot for the zero-terminator.
1158 */
1159 params.freqs = os_malloc(sizeof(int) * 2);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001160 if (params.freqs) {
1161 params.freqs[0] = wpa_s->assoc_freq;
1162 params.freqs[1] = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07001163 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07001164
1165 /*
1166 * Reset the reattach flag so that we fall back to full scan if
1167 * this scan fails.
1168 */
1169 wpa_s->reattach = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001170 } else {
1171 struct wpa_ssid *start = ssid, *tssid;
1172 int freqs_set = 0;
1173 if (ssid == NULL && max_ssids > 1)
1174 ssid = wpa_s->conf->ssid;
1175 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001176 if (!wpas_network_disabled(wpa_s, ssid) &&
1177 ssid->scan_ssid) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001178 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
1179 ssid->ssid, ssid->ssid_len);
1180 params.ssids[params.num_ssids].ssid =
1181 ssid->ssid;
1182 params.ssids[params.num_ssids].ssid_len =
1183 ssid->ssid_len;
1184 params.num_ssids++;
1185 if (params.num_ssids + 1 >= max_ssids)
1186 break;
1187 }
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001188
1189 if (!wpas_network_disabled(wpa_s, ssid)) {
1190 /*
1191 * Also add the SSID of the OWE BSS, to allow
1192 * discovery of transition mode APs more
1193 * quickly.
1194 */
1195 wpa_add_owe_scan_ssid(wpa_s, &params, ssid,
1196 max_ssids);
1197 }
1198
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001199 ssid = ssid->next;
1200 if (ssid == start)
1201 break;
1202 if (ssid == NULL && max_ssids > 1 &&
1203 start != wpa_s->conf->ssid)
1204 ssid = wpa_s->conf->ssid;
1205 }
1206
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001207 if (wpa_s->scan_id_count &&
1208 wpa_s->last_scan_req == MANUAL_SCAN_REQ)
1209 wpa_set_scan_ssids(wpa_s, &params, max_ssids);
1210
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001211 for (tssid = wpa_s->conf->ssid;
1212 wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid;
1213 tssid = tssid->next) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001214 if (wpas_network_disabled(wpa_s, tssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001215 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07001216 if (((params.freqs || !freqs_set) &&
1217 tssid->scan_freq) &&
1218 int_array_len(params.freqs) < 100) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001219 int_array_concat(&params.freqs,
1220 tssid->scan_freq);
1221 } else {
1222 os_free(params.freqs);
1223 params.freqs = NULL;
1224 }
1225 freqs_set = 1;
1226 }
1227 int_array_sort_unique(params.freqs);
1228 }
1229
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001230 if (ssid && max_ssids == 1) {
1231 /*
1232 * If the driver is limited to 1 SSID at a time interleave
1233 * wildcard SSID scans with specific SSID scans to avoid
1234 * waiting a long time for a wildcard scan.
1235 */
1236 if (!wpa_s->prev_scan_wildcard) {
1237 params.ssids[0].ssid = NULL;
1238 params.ssids[0].ssid_len = 0;
1239 wpa_s->prev_scan_wildcard = 1;
1240 wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
1241 "wildcard SSID (Interleave with specific)");
1242 } else {
1243 wpa_s->prev_scan_ssid = ssid;
1244 wpa_s->prev_scan_wildcard = 0;
1245 wpa_dbg(wpa_s, MSG_DEBUG,
1246 "Starting AP scan for specific SSID: %s",
1247 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001248 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001249 } else if (ssid) {
1250 /* max_ssids > 1 */
1251
1252 wpa_s->prev_scan_ssid = ssid;
1253 wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
1254 "the scan request");
1255 params.num_ssids++;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001256 } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
1257 wpa_s->manual_scan_passive && params.num_ssids == 0) {
1258 wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001259 } else if (wpa_s->conf->passive_scan) {
1260 wpa_dbg(wpa_s, MSG_DEBUG,
1261 "Use passive scan based on configuration");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001262 } else {
1263 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
1264 params.num_ssids++;
1265 wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
1266 "SSID");
1267 }
1268
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07001269ssid_list_set:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001270 wpa_supplicant_optimize_freqs(wpa_s, &params);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001271 extra_ie = wpa_supplicant_extra_ies(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001272
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001273 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001274 wpa_s->manual_scan_only_new) {
1275 wpa_printf(MSG_DEBUG,
1276 "Request driver to clear scan cache due to manual only_new=1 scan");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001277 params.only_new_results = 1;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001278 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001279
1280 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
1281 wpa_s->manual_scan_freqs) {
1282 wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
1283 params.freqs = wpa_s->manual_scan_freqs;
1284 wpa_s->manual_scan_freqs = NULL;
1285 }
1286
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001287 if (params.freqs == NULL && wpa_s->select_network_scan_freqs) {
1288 wpa_dbg(wpa_s, MSG_DEBUG,
1289 "Limit select_network scan to specified channels");
1290 params.freqs = wpa_s->select_network_scan_freqs;
1291 wpa_s->select_network_scan_freqs = NULL;
1292 }
1293
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001294 if (params.freqs == NULL && wpa_s->next_scan_freqs) {
1295 wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
1296 "generated frequency list");
1297 params.freqs = wpa_s->next_scan_freqs;
1298 } else
1299 os_free(wpa_s->next_scan_freqs);
1300 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001301 wpa_setband_scan_freqs(wpa_s, &params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001302
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07001303 /* See if user specified frequencies. If so, scan only those. */
Hai Shalom60840252021-02-19 19:02:11 -08001304 if (wpa_s->last_scan_req == INITIAL_SCAN_REQ &&
1305 wpa_s->conf->initial_freq_list && !params.freqs) {
1306 wpa_dbg(wpa_s, MSG_DEBUG,
1307 "Optimize scan based on conf->initial_freq_list");
1308 int_array_concat(&params.freqs, wpa_s->conf->initial_freq_list);
1309 } else if (wpa_s->conf->freq_list && !params.freqs) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07001310 wpa_dbg(wpa_s, MSG_DEBUG,
1311 "Optimize scan based on conf->freq_list");
1312 int_array_concat(&params.freqs, wpa_s->conf->freq_list);
1313 }
1314
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001315 /* Use current associated channel? */
1316 if (wpa_s->conf->scan_cur_freq && !params.freqs) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001317 unsigned int num = wpa_s->num_multichan_concurrent;
1318
1319 params.freqs = os_calloc(num + 1, sizeof(int));
1320 if (params.freqs) {
1321 num = get_shared_radio_freqs(wpa_s, params.freqs, num);
1322 if (num > 0) {
1323 wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
1324 "current operating channels since "
1325 "scan_cur_freq is enabled");
1326 } else {
1327 os_free(params.freqs);
1328 params.freqs = NULL;
1329 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001330 }
1331 }
1332
Hai Shalomce48b4a2018-09-05 11:41:35 -07001333#ifdef CONFIG_MBO
1334 if (wpa_s->enable_oce & OCE_STA)
1335 params.oce_scan = 1;
1336#endif /* CONFIG_MBO */
1337
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001338 params.filter_ssids = wpa_supplicant_build_filter_ssids(
1339 wpa_s->conf, &params.num_filter_ssids);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001340 if (extra_ie) {
1341 params.extra_ies = wpabuf_head(extra_ie);
1342 params.extra_ies_len = wpabuf_len(extra_ie);
1343 }
1344
1345#ifdef CONFIG_P2P
Dmitry Shmidt413dde72014-04-11 10:23:22 -07001346 if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation ||
Dmitry Shmidt04949592012-07-19 12:16:46 -07001347 (wpa_s->show_group_started && wpa_s->go_params)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001348 /*
1349 * The interface may not yet be in P2P mode, so we have to
1350 * explicitly request P2P probe to disable CCK rates.
1351 */
1352 params.p2p_probe = 1;
1353 }
1354#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001355
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001356 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001357 wpa_s->wpa_state <= WPA_SCANNING)
1358 wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_scan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001359
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001360 if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
1361 struct wpa_bss *bss;
1362
1363 params.bssid = wpa_s->next_scan_bssid;
1364 bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
Hai Shalomfdcde762020-04-02 11:19:20 -07001365 if (!wpa_s->next_scan_bssid_wildcard_ssid &&
1366 bss && bss->ssid_len && params.num_ssids == 1 &&
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001367 params.ssids[0].ssid_len == 0) {
1368 params.ssids[0].ssid = bss->ssid;
1369 params.ssids[0].ssid_len = bss->ssid_len;
1370 wpa_dbg(wpa_s, MSG_DEBUG,
1371 "Scan a previously specified BSSID " MACSTR
1372 " and SSID %s",
1373 MAC2STR(params.bssid),
1374 wpa_ssid_txt(bss->ssid, bss->ssid_len));
1375 } else {
1376 wpa_dbg(wpa_s, MSG_DEBUG,
1377 "Scan a previously specified BSSID " MACSTR,
1378 MAC2STR(params.bssid));
1379 }
1380 }
1381
Sunil8cd6f4d2022-06-28 18:40:46 +00001382 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
1383 wpa_s->manual_non_coloc_6ghz) {
1384 wpa_dbg(wpa_s, MSG_DEBUG, "Collocated 6 GHz logic is disabled");
1385 params.non_coloc_6ghz = 1;
1386 }
1387
Dmitry Shmidt04949592012-07-19 12:16:46 -07001388 scan_params = &params;
1389
1390scan:
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001391#ifdef CONFIG_P2P
1392 /*
1393 * If the driver does not support multi-channel concurrency and a
1394 * virtual interface that shares the same radio with the wpa_s interface
1395 * is operating there may not be need to scan other channels apart from
1396 * the current operating channel on the other virtual interface. Filter
1397 * out other channels in case we are trying to find a connection for a
1398 * station interface when we are not configured to prefer station
1399 * connection and a concurrent operation is already in process.
1400 */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001401 if (wpa_s->scan_for_connection &&
1402 wpa_s->last_scan_req == NORMAL_SCAN_REQ &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001403 !scan_params->freqs && !params.freqs &&
1404 wpas_is_p2p_prioritized(wpa_s) &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001405 wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
1406 non_p2p_network_enabled(wpa_s)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001407 unsigned int num = wpa_s->num_multichan_concurrent;
1408
1409 params.freqs = os_calloc(num + 1, sizeof(int));
1410 if (params.freqs) {
1411 num = get_shared_radio_freqs(wpa_s, params.freqs, num);
1412 if (num > 0 && num == wpa_s->num_multichan_concurrent) {
1413 wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
1414 } else {
1415 os_free(params.freqs);
1416 params.freqs = NULL;
1417 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001418 }
1419 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001420
1421 if (!params.freqs &&
1422 (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning) &&
1423 !is_p2p_allow_6ghz(wpa_s->global->p2p) &&
1424 is_6ghz_supported(wpa_s)) {
Jimmy Chenafee24e2022-06-17 22:53:15 +08001425 /* Exclude 6 GHz channels from the full scan for P2P connection
Hai Shaloma20dcd72022-02-04 13:43:00 -08001426 * since the 6 GHz band is disabled for P2P uses. */
1427 wpa_printf(MSG_DEBUG,
1428 "P2P: 6 GHz disabled - update the scan frequency list");
Matthew Wang36173112022-11-07 21:48:44 -08001429 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params, false, false);
1430 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, &params, false, false);
1431 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211AD, &params, false, false);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001432 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001433#endif /* CONFIG_P2P */
1434
Dmitry Shmidt04949592012-07-19 12:16:46 -07001435 ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001436
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001437 if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
1438 !wpa_s->manual_scan_freqs) {
1439 /* Restore manual_scan_freqs for the next attempt */
1440 wpa_s->manual_scan_freqs = params.freqs;
1441 params.freqs = NULL;
1442 }
1443
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001444 wpabuf_free(extra_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001445 os_free(params.freqs);
1446 os_free(params.filter_ssids);
Hai Shalomc3565922019-10-28 11:58:20 -07001447 os_free(params.mac_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001448
1449 if (ret) {
1450 wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001451 if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
1452 wpa_supplicant_set_state(wpa_s,
1453 wpa_s->scan_prev_wpa_state);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001454 /* Restore scan_req since we will try to scan again */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001455 wpa_s->scan_req = wpa_s->last_scan_req;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001456 wpa_supplicant_req_scan(wpa_s, 1, 0);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001457 } else {
1458 wpa_s->scan_for_connection = 0;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001459#ifdef CONFIG_INTERWORKING
1460 wpa_s->interworking_fast_assoc_tried = 0;
1461#endif /* CONFIG_INTERWORKING */
Hai Shalomfdcde762020-04-02 11:19:20 -07001462 wpa_s->next_scan_bssid_wildcard_ssid = 0;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001463 if (params.bssid)
1464 os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001465 }
1466}
1467
1468
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001469void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
1470{
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001471 struct os_reltime remaining, new_int;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001472 int cancelled;
1473
1474 cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
1475 &remaining);
1476
1477 new_int.sec = sec;
1478 new_int.usec = 0;
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001479 if (cancelled && os_reltime_before(&remaining, &new_int)) {
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001480 new_int.sec = remaining.sec;
1481 new_int.usec = remaining.usec;
1482 }
1483
Dmitry Shmidt051af732013-10-22 13:52:46 -07001484 if (cancelled) {
1485 eloop_register_timeout(new_int.sec, new_int.usec,
1486 wpa_supplicant_scan, wpa_s, NULL);
1487 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001488 wpa_s->scan_interval = sec;
1489}
1490
1491
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001492/**
1493 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
1494 * @wpa_s: Pointer to wpa_supplicant data
1495 * @sec: Number of seconds after which to scan
1496 * @usec: Number of microseconds after which to scan
1497 *
1498 * This function is used to schedule a scan for neighboring access points after
1499 * the specified time.
1500 */
1501void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
1502{
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001503 int res;
1504
1505 if (wpa_s->p2p_mgmt) {
1506 wpa_dbg(wpa_s, MSG_DEBUG,
1507 "Ignore scan request (%d.%06d sec) on p2p_mgmt interface",
1508 sec, usec);
1509 return;
1510 }
1511
1512 res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
1513 NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001514 if (res == 1) {
1515 wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001516 sec, usec);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001517 } else if (res == 0) {
1518 wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner",
1519 sec, usec);
1520 } else {
1521 wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec",
1522 sec, usec);
1523 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001524 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001525}
1526
1527
1528/**
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001529 * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan
1530 * @wpa_s: Pointer to wpa_supplicant data
1531 * @sec: Number of seconds after which to scan
1532 * @usec: Number of microseconds after which to scan
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001533 * Returns: 0 on success or -1 otherwise
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001534 *
1535 * This function is used to schedule periodic scans for neighboring
1536 * access points after the specified time.
1537 */
1538int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
1539 int sec, int usec)
1540{
1541 if (!wpa_s->sched_scan_supported)
1542 return -1;
1543
1544 eloop_register_timeout(sec, usec,
1545 wpa_supplicant_delayed_sched_scan_timeout,
1546 wpa_s, NULL);
1547
1548 return 0;
1549}
1550
1551
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001552static void
1553wpa_scan_set_relative_rssi_params(struct wpa_supplicant *wpa_s,
1554 struct wpa_driver_scan_params *params)
1555{
1556 if (wpa_s->wpa_state != WPA_COMPLETED ||
1557 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI) ||
1558 wpa_s->srp.relative_rssi_set == 0)
1559 return;
1560
1561 params->relative_rssi_set = 1;
1562 params->relative_rssi = wpa_s->srp.relative_rssi;
1563
1564 if (wpa_s->srp.relative_adjust_rssi == 0)
1565 return;
1566
1567 params->relative_adjust_band = wpa_s->srp.relative_adjust_band;
1568 params->relative_adjust_rssi = wpa_s->srp.relative_adjust_rssi;
1569}
1570
1571
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001572/**
1573 * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
1574 * @wpa_s: Pointer to wpa_supplicant data
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001575 * Returns: 0 is sched_scan was started or -1 otherwise
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001576 *
1577 * This function is used to schedule periodic scans for neighboring
1578 * access points repeating the scan continuously.
1579 */
1580int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
1581{
1582 struct wpa_driver_scan_params params;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001583 struct wpa_driver_scan_params *scan_params;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001584 enum wpa_states prev_state;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001585 struct wpa_ssid *ssid = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001586 struct wpabuf *extra_ie = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001587 int ret;
1588 unsigned int max_sched_scan_ssids;
1589 int wildcard = 0;
1590 int need_ssids;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001591 struct sched_scan_plan scan_plan;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001592
1593 if (!wpa_s->sched_scan_supported)
1594 return -1;
1595
1596 if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
1597 max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
1598 else
1599 max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001600 if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001601 return -1;
1602
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001603 wpa_s->sched_scan_stop_req = 0;
1604
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001605 if (wpa_s->sched_scanning) {
1606 wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
1607 return 0;
1608 }
1609
1610 need_ssids = 0;
1611 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001612 if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001613 /* Use wildcard SSID to find this network */
1614 wildcard = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001615 } else if (!wpas_network_disabled(wpa_s, ssid) &&
1616 ssid->ssid_len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001617 need_ssids++;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001618
1619#ifdef CONFIG_WPS
1620 if (!wpas_network_disabled(wpa_s, ssid) &&
1621 ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
1622 /*
1623 * Normal scan is more reliable and faster for WPS
1624 * operations and since these are for short periods of
1625 * time, the benefit of trying to use sched_scan would
1626 * be limited.
1627 */
1628 wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
1629 "sched_scan for WPS");
1630 return -1;
1631 }
1632#endif /* CONFIG_WPS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001633 }
1634 if (wildcard)
1635 need_ssids++;
1636
1637 if (wpa_s->normal_scans < 3 &&
1638 (need_ssids <= wpa_s->max_scan_ssids ||
1639 wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
1640 /*
1641 * When normal scan can speed up operations, use that for the
1642 * first operations before starting the sched_scan to allow
1643 * user space sleep more. We do this only if the normal scan
1644 * has functionality that is suitable for this or if the
1645 * sched_scan does not have better support for multiple SSIDs.
1646 */
1647 wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
1648 "sched_scan for initial scans (normal_scans=%d)",
1649 wpa_s->normal_scans);
1650 return -1;
1651 }
1652
1653 os_memset(&params, 0, sizeof(params));
1654
1655 /* If we can't allocate space for the filters, we just don't filter */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001656 params.filter_ssids = os_calloc(wpa_s->max_match_sets,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001657 sizeof(struct wpa_driver_scan_filter));
1658
1659 prev_state = wpa_s->wpa_state;
1660 if (wpa_s->wpa_state == WPA_DISCONNECTED ||
1661 wpa_s->wpa_state == WPA_INACTIVE)
1662 wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
1663
Dmitry Shmidt04949592012-07-19 12:16:46 -07001664 if (wpa_s->autoscan_params != NULL) {
1665 scan_params = wpa_s->autoscan_params;
1666 goto scan;
1667 }
1668
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001669 /* Find the starting point from which to continue scanning */
1670 ssid = wpa_s->conf->ssid;
1671 if (wpa_s->prev_sched_ssid) {
1672 while (ssid) {
1673 if (ssid == wpa_s->prev_sched_ssid) {
1674 ssid = ssid->next;
1675 break;
1676 }
1677 ssid = ssid->next;
1678 }
1679 }
1680
1681 if (!ssid || !wpa_s->prev_sched_ssid) {
1682 wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001683 wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
1684 wpa_s->first_sched_scan = 1;
1685 ssid = wpa_s->conf->ssid;
1686 wpa_s->prev_sched_ssid = ssid;
1687 }
1688
1689 if (wildcard) {
1690 wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
1691 params.num_ssids++;
1692 }
1693
1694 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001695 if (wpas_network_disabled(wpa_s, ssid))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001696 goto next;
1697
1698 if (params.num_filter_ssids < wpa_s->max_match_sets &&
1699 params.filter_ssids && ssid->ssid && ssid->ssid_len) {
1700 wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
1701 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1702 os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
1703 ssid->ssid, ssid->ssid_len);
1704 params.filter_ssids[params.num_filter_ssids].ssid_len =
1705 ssid->ssid_len;
1706 params.num_filter_ssids++;
1707 } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
1708 {
1709 wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
1710 "filter for sched_scan - drop filter");
1711 os_free(params.filter_ssids);
1712 params.filter_ssids = NULL;
1713 params.num_filter_ssids = 0;
1714 }
1715
1716 if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
1717 if (params.num_ssids == max_sched_scan_ssids)
1718 break; /* only room for broadcast SSID */
1719 wpa_dbg(wpa_s, MSG_DEBUG,
1720 "add to active scan ssid: %s",
1721 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1722 params.ssids[params.num_ssids].ssid =
1723 ssid->ssid;
1724 params.ssids[params.num_ssids].ssid_len =
1725 ssid->ssid_len;
1726 params.num_ssids++;
1727 if (params.num_ssids >= max_sched_scan_ssids) {
1728 wpa_s->prev_sched_ssid = ssid;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001729 do {
1730 ssid = ssid->next;
1731 } while (ssid &&
1732 (wpas_network_disabled(wpa_s, ssid) ||
1733 !ssid->scan_ssid));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001734 break;
1735 }
1736 }
1737
1738 next:
1739 wpa_s->prev_sched_ssid = ssid;
1740 ssid = ssid->next;
1741 }
1742
1743 if (params.num_filter_ssids == 0) {
1744 os_free(params.filter_ssids);
1745 params.filter_ssids = NULL;
1746 }
1747
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001748 extra_ie = wpa_supplicant_extra_ies(wpa_s);
1749 if (extra_ie) {
1750 params.extra_ies = wpabuf_head(extra_ie);
1751 params.extra_ies_len = wpabuf_len(extra_ie);
1752 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001753
Dmitry Shmidt18463232014-01-24 12:29:41 -08001754 if (wpa_s->conf->filter_rssi)
1755 params.filter_rssi = wpa_s->conf->filter_rssi;
1756
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001757 /* See if user specified frequencies. If so, scan only those. */
1758 if (wpa_s->conf->freq_list && !params.freqs) {
1759 wpa_dbg(wpa_s, MSG_DEBUG,
1760 "Optimize scan based on conf->freq_list");
1761 int_array_concat(&params.freqs, wpa_s->conf->freq_list);
1762 }
1763
Hai Shalomce48b4a2018-09-05 11:41:35 -07001764#ifdef CONFIG_MBO
1765 if (wpa_s->enable_oce & OCE_STA)
1766 params.oce_scan = 1;
1767#endif /* CONFIG_MBO */
1768
Dmitry Shmidt04949592012-07-19 12:16:46 -07001769 scan_params = &params;
1770
1771scan:
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001772 wpa_s->sched_scan_timed_out = 0;
1773
1774 /*
1775 * We cannot support multiple scan plans if the scan request includes
1776 * too many SSID's, so in this case use only the last scan plan and make
1777 * it run infinitely. It will be stopped by the timeout.
1778 */
1779 if (wpa_s->sched_scan_plans_num == 1 ||
1780 (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) {
1781 params.sched_scan_plans = wpa_s->sched_scan_plans;
1782 params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
1783 } else if (wpa_s->sched_scan_plans_num > 1) {
1784 wpa_dbg(wpa_s, MSG_DEBUG,
1785 "Too many SSIDs. Default to using single scheduled_scan plan");
1786 params.sched_scan_plans =
1787 &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num -
1788 1];
1789 params.sched_scan_plans_num = 1;
1790 } else {
1791 if (wpa_s->conf->sched_scan_interval)
1792 scan_plan.interval = wpa_s->conf->sched_scan_interval;
1793 else
1794 scan_plan.interval = 10;
1795
1796 if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) {
1797 wpa_printf(MSG_WARNING,
1798 "Scan interval too long(%u), use the maximum allowed(%u)",
1799 scan_plan.interval,
1800 wpa_s->max_sched_scan_plan_interval);
1801 scan_plan.interval =
1802 wpa_s->max_sched_scan_plan_interval;
1803 }
1804
1805 scan_plan.iterations = 0;
1806 params.sched_scan_plans = &scan_plan;
1807 params.sched_scan_plans_num = 1;
1808 }
1809
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001810 params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay;
1811
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001812 if (ssid || !wpa_s->first_sched_scan) {
1813 wpa_dbg(wpa_s, MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001814 "Starting sched scan after %u seconds: interval %u timeout %d",
1815 params.sched_scan_start_delay,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001816 params.sched_scan_plans[0].interval,
1817 wpa_s->sched_scan_timeout);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001818 } else {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001819 wpa_dbg(wpa_s, MSG_DEBUG,
1820 "Starting sched scan after %u seconds (no timeout)",
1821 params.sched_scan_start_delay);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001822 }
1823
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001824 wpa_setband_scan_freqs(wpa_s, scan_params);
1825
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001826 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001827 wpa_s->wpa_state <= WPA_SCANNING)
1828 wpa_setup_mac_addr_rand_params(&params,
1829 wpa_s->mac_addr_sched_scan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001830
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001831 wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
1832
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001833 ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001834 wpabuf_free(extra_ie);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001835 os_free(params.filter_ssids);
Hai Shalomc3565922019-10-28 11:58:20 -07001836 os_free(params.mac_addr);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001837 if (ret) {
1838 wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
1839 if (prev_state != wpa_s->wpa_state)
1840 wpa_supplicant_set_state(wpa_s, prev_state);
1841 return ret;
1842 }
1843
1844 /* If we have more SSIDs to scan, add a timeout so we scan them too */
1845 if (ssid || !wpa_s->first_sched_scan) {
1846 wpa_s->sched_scan_timed_out = 0;
1847 eloop_register_timeout(wpa_s->sched_scan_timeout, 0,
1848 wpa_supplicant_sched_scan_timeout,
1849 wpa_s, NULL);
1850 wpa_s->first_sched_scan = 0;
1851 wpa_s->sched_scan_timeout /= 2;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001852 params.sched_scan_plans[0].interval *= 2;
1853 if ((unsigned int) wpa_s->sched_scan_timeout <
1854 params.sched_scan_plans[0].interval ||
1855 params.sched_scan_plans[0].interval >
1856 wpa_s->max_sched_scan_plan_interval) {
1857 params.sched_scan_plans[0].interval = 10;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001858 wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
1859 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001860 }
1861
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001862 /* If there is no more ssids, start next time from the beginning */
1863 if (!ssid)
1864 wpa_s->prev_sched_ssid = NULL;
1865
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001866 return 0;
1867}
1868
1869
1870/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001871 * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
1872 * @wpa_s: Pointer to wpa_supplicant data
1873 *
1874 * This function is used to cancel a scan request scheduled with
1875 * wpa_supplicant_req_scan().
1876 */
1877void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
1878{
1879 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
1880 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001881}
1882
1883
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001884/**
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001885 * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan
1886 * @wpa_s: Pointer to wpa_supplicant data
1887 *
1888 * This function is used to stop a delayed scheduled scan.
1889 */
1890void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)
1891{
1892 if (!wpa_s->sched_scan_supported)
1893 return;
1894
1895 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan");
1896 eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout,
1897 wpa_s, NULL);
1898}
1899
1900
1901/**
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001902 * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
1903 * @wpa_s: Pointer to wpa_supplicant data
1904 *
1905 * This function is used to stop a periodic scheduled scan.
1906 */
1907void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
1908{
1909 if (!wpa_s->sched_scanning)
1910 return;
1911
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001912 if (wpa_s->sched_scanning)
1913 wpa_s->sched_scan_stop_req = 1;
1914
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001915 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
1916 eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
1917 wpa_supplicant_stop_sched_scan(wpa_s);
1918}
1919
1920
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001921/**
1922 * wpa_supplicant_notify_scanning - Indicate possible scan state change
1923 * @wpa_s: Pointer to wpa_supplicant data
1924 * @scanning: Whether scanning is currently in progress
1925 *
1926 * This function is to generate scanning notifycations. It is called whenever
1927 * there may have been a change in scanning (scan started, completed, stopped).
1928 * wpas_notify_scanning() is called whenever the scanning state changed from the
1929 * previously notified state.
1930 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001931void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
1932 int scanning)
1933{
1934 if (wpa_s->scanning != scanning) {
1935 wpa_s->scanning = scanning;
1936 wpas_notify_scanning(wpa_s);
1937 }
1938}
1939
1940
1941static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
1942{
1943 int rate = 0;
1944 const u8 *ie;
1945 int i;
1946
1947 ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
1948 for (i = 0; ie && i < ie[1]; i++) {
1949 if ((ie[i + 2] & 0x7f) > rate)
1950 rate = ie[i + 2] & 0x7f;
1951 }
1952
1953 ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
1954 for (i = 0; ie && i < ie[1]; i++) {
1955 if ((ie[i + 2] & 0x7f) > rate)
1956 rate = ie[i + 2] & 0x7f;
1957 }
1958
1959 return rate;
1960}
1961
1962
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001963/**
1964 * wpa_scan_get_ie - Fetch a specified information element from a scan result
1965 * @res: Scan result entry
1966 * @ie: Information element identitifier (WLAN_EID_*)
1967 * Returns: Pointer to the information element (id field) or %NULL if not found
1968 *
1969 * This function returns the first matching information element in the scan
1970 * result.
1971 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001972const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
1973{
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001974 size_t ie_len = res->ie_len;
1975
1976 /* Use the Beacon frame IEs if res->ie_len is not available */
1977 if (!ie_len)
1978 ie_len = res->beacon_ie_len;
1979
1980 return get_ie((const u8 *) (res + 1), ie_len, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001981}
1982
1983
Sunil Ravi89eba102022-09-13 21:04:37 -07001984const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type)
1985{
1986 size_t ie_len = res->ie_len;
1987
1988 /* Use the Beacon frame IEs if res->ie_len is not available */
1989 if (!ie_len)
1990 ie_len = res->beacon_ie_len;
1991
1992 return get_ml_ie((const u8 *) (res + 1), ie_len, type);
1993}
1994
1995
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001996/**
1997 * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
1998 * @res: Scan result entry
1999 * @vendor_type: Vendor type (four octets starting the IE payload)
2000 * Returns: Pointer to the information element (id field) or %NULL if not found
2001 *
2002 * This function returns the first matching information element in the scan
2003 * result.
2004 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002005const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
2006 u32 vendor_type)
2007{
Hai Shalom60840252021-02-19 19:02:11 -08002008 const u8 *ies;
2009 const struct element *elem;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002010
Hai Shalom60840252021-02-19 19:02:11 -08002011 ies = (const u8 *) (res + 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002012
Hai Shalom60840252021-02-19 19:02:11 -08002013 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, res->ie_len) {
2014 if (elem->datalen >= 4 &&
2015 vendor_type == WPA_GET_BE32(elem->data))
2016 return &elem->id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002017 }
2018
2019 return NULL;
2020}
2021
2022
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002023/**
Dmitry Shmidt96571392013-10-14 12:54:46 -07002024 * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
2025 * @res: Scan result entry
2026 * @vendor_type: Vendor type (four octets starting the IE payload)
2027 * Returns: Pointer to the information element (id field) or %NULL if not found
2028 *
2029 * This function returns the first matching information element in the scan
2030 * result.
2031 *
2032 * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
2033 * from Beacon frames instead of either Beacon or Probe Response frames.
2034 */
2035const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
2036 u32 vendor_type)
2037{
Hai Shalom60840252021-02-19 19:02:11 -08002038 const u8 *ies;
2039 const struct element *elem;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002040
2041 if (res->beacon_ie_len == 0)
2042 return NULL;
2043
Hai Shalom60840252021-02-19 19:02:11 -08002044 ies = (const u8 *) (res + 1);
2045 ies += res->ie_len;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002046
Hai Shalom60840252021-02-19 19:02:11 -08002047 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
2048 res->beacon_ie_len) {
2049 if (elem->datalen >= 4 &&
2050 vendor_type == WPA_GET_BE32(elem->data))
2051 return &elem->id;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002052 }
2053
2054 return NULL;
2055}
2056
2057
2058/**
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002059 * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
2060 * @res: Scan result entry
2061 * @vendor_type: Vendor type (four octets starting the IE payload)
2062 * Returns: Pointer to the information element payload or %NULL if not found
2063 *
2064 * This function returns concatenated payload of possibly fragmented vendor
2065 * specific information elements in the scan result. The caller is responsible
2066 * for freeing the returned buffer.
2067 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002068struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
2069 u32 vendor_type)
2070{
2071 struct wpabuf *buf;
2072 const u8 *end, *pos;
2073
2074 buf = wpabuf_alloc(res->ie_len);
2075 if (buf == NULL)
2076 return NULL;
2077
2078 pos = (const u8 *) (res + 1);
2079 end = pos + res->ie_len;
2080
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002081 while (end - pos > 1) {
Hai Shalom60840252021-02-19 19:02:11 -08002082 u8 ie, len;
2083
2084 ie = pos[0];
2085 len = pos[1];
2086 if (len > end - pos - 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002087 break;
Hai Shalom60840252021-02-19 19:02:11 -08002088 pos += 2;
2089 if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
2090 vendor_type == WPA_GET_BE32(pos))
2091 wpabuf_put_data(buf, pos + 4, len - 4);
2092 pos += len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002093 }
2094
2095 if (wpabuf_len(buf) == 0) {
2096 wpabuf_free(buf);
2097 buf = NULL;
2098 }
2099
2100 return buf;
2101}
2102
2103
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002104/* Compare function for sorting scan results. Return >0 if @b is considered
2105 * better. */
2106static int wpa_scan_result_compar(const void *a, const void *b)
2107{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002108#define MIN(a,b) a < b ? a : b
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002109 struct wpa_scan_res **_wa = (void *) a;
2110 struct wpa_scan_res **_wb = (void *) b;
2111 struct wpa_scan_res *wa = *_wa;
2112 struct wpa_scan_res *wb = *_wb;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002113 int wpa_a, wpa_b;
2114 int snr_a, snr_b, snr_a_full, snr_b_full;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002115
2116 /* WPA/WPA2 support preferred */
2117 wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
2118 wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
2119 wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
2120 wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
2121
2122 if (wpa_b && !wpa_a)
2123 return 1;
2124 if (!wpa_b && wpa_a)
2125 return -1;
2126
2127 /* privacy support preferred */
2128 if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
2129 (wb->caps & IEEE80211_CAP_PRIVACY))
2130 return 1;
2131 if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
2132 (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
2133 return -1;
2134
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002135 if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002136 snr_a_full = wa->snr;
2137 snr_a = MIN(wa->snr, GREAT_SNR);
2138 snr_b_full = wb->snr;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002139 snr_b = MIN(wb->snr, GREAT_SNR);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002140 } else {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002141 /* Level is not in dBm, so we can't calculate
2142 * SNR. Just use raw level (units unknown). */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002143 snr_a = snr_a_full = wa->level;
2144 snr_b = snr_b_full = wb->level;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002145 }
2146
Hai Shaloma20dcd72022-02-04 13:43:00 -08002147 /* If SNR is close, decide by max rate or frequency band. For cases
2148 * involving the 6 GHz band, use the throughput estimate irrespective
2149 * of the SNR difference since the LPI/VLP rules may result in
2150 * significant differences in SNR for cases where the estimated
2151 * throughput can be considerably higher with the lower SNR. */
2152 if (snr_a && snr_b && (abs(snr_b - snr_a) < 7 ||
2153 is_6ghz_freq(wa->freq) ||
2154 is_6ghz_freq(wb->freq))) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002155 if (wa->est_throughput != wb->est_throughput)
Hai Shalom021b0b52019-04-10 11:17:58 -07002156 return (int) wb->est_throughput -
2157 (int) wa->est_throughput;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002158 }
2159 if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
2160 (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002161 if (is_6ghz_freq(wa->freq) ^ is_6ghz_freq(wb->freq))
2162 return is_6ghz_freq(wa->freq) ? -1 : 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002163 if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
2164 return IS_5GHZ(wa->freq) ? -1 : 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002165 }
2166
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002167 /* all things being equal, use SNR; if SNRs are
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002168 * identical, use quality values since some drivers may only report
2169 * that value and leave the signal level zero */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002170 if (snr_b_full == snr_a_full)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002171 return wb->qual - wa->qual;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002172 return snr_b_full - snr_a_full;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002173#undef MIN
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002174}
2175
2176
2177#ifdef CONFIG_WPS
2178/* Compare function for sorting scan results when searching a WPS AP for
2179 * provisioning. Return >0 if @b is considered better. */
2180static int wpa_scan_result_wps_compar(const void *a, const void *b)
2181{
2182 struct wpa_scan_res **_wa = (void *) a;
2183 struct wpa_scan_res **_wb = (void *) b;
2184 struct wpa_scan_res *wa = *_wa;
2185 struct wpa_scan_res *wb = *_wb;
2186 int uses_wps_a, uses_wps_b;
2187 struct wpabuf *wps_a, *wps_b;
2188 int res;
2189
2190 /* Optimization - check WPS IE existence before allocated memory and
2191 * doing full reassembly. */
2192 uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
2193 uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
2194 if (uses_wps_a && !uses_wps_b)
2195 return -1;
2196 if (!uses_wps_a && uses_wps_b)
2197 return 1;
2198
2199 if (uses_wps_a && uses_wps_b) {
2200 wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
2201 wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
2202 res = wps_ap_priority_compar(wps_a, wps_b);
2203 wpabuf_free(wps_a);
2204 wpabuf_free(wps_b);
2205 if (res)
2206 return res;
2207 }
2208
2209 /*
2210 * Do not use current AP security policy as a sorting criteria during
2211 * WPS provisioning step since the AP may get reconfigured at the
2212 * completion of provisioning.
2213 */
2214
2215 /* all things being equal, use signal level; if signal levels are
2216 * identical, use quality values since some drivers may only report
2217 * that value and leave the signal level zero */
2218 if (wb->level == wa->level)
2219 return wb->qual - wa->qual;
2220 return wb->level - wa->level;
2221}
2222#endif /* CONFIG_WPS */
2223
2224
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002225static void dump_scan_res(struct wpa_scan_results *scan_res)
2226{
2227#ifndef CONFIG_NO_STDOUT_DEBUG
2228 size_t i;
2229
2230 if (scan_res->res == NULL || scan_res->num == 0)
2231 return;
2232
2233 wpa_printf(MSG_EXCESSIVE, "Sorted scan results");
2234
2235 for (i = 0; i < scan_res->num; i++) {
2236 struct wpa_scan_res *r = scan_res->res[i];
Dmitry Shmidt04949592012-07-19 12:16:46 -07002237 u8 *pos;
Sunil Ravia04bd252022-05-02 22:54:18 -07002238 const u8 *ssid_ie, *ssid = NULL;
2239 size_t ssid_len = 0;
2240
2241 ssid_ie = wpa_scan_get_ie(r, WLAN_EID_SSID);
2242 if (ssid_ie) {
2243 ssid = ssid_ie + 2;
2244 ssid_len = ssid_ie[1];
2245 }
2246
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002247 if (r->flags & WPA_SCAN_LEVEL_DBM) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002248 int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
2249
Sunil Ravia04bd252022-05-02 22:54:18 -07002250 wpa_printf(MSG_EXCESSIVE, MACSTR
2251 " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
2252 MAC2STR(r->bssid),
2253 wpa_ssid_txt(ssid, ssid_len),
2254 r->freq, r->qual,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002255 r->noise, noise_valid ? "" : "~", r->level,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002256 r->snr, r->snr >= GREAT_SNR ? "*" : "",
2257 r->flags,
2258 r->age, r->est_throughput);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002259 } else {
Sunil Ravia04bd252022-05-02 22:54:18 -07002260 wpa_printf(MSG_EXCESSIVE, MACSTR
2261 " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u",
2262 MAC2STR(r->bssid),
2263 wpa_ssid_txt(ssid, ssid_len),
2264 r->freq, r->qual,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002265 r->noise, r->level, r->flags, r->age,
2266 r->est_throughput);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002267 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002268 pos = (u8 *) (r + 1);
2269 if (r->ie_len)
2270 wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
2271 pos += r->ie_len;
2272 if (r->beacon_ie_len)
2273 wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
2274 pos, r->beacon_ie_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002275 }
2276#endif /* CONFIG_NO_STDOUT_DEBUG */
2277}
2278
2279
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002280/**
2281 * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed
2282 * @wpa_s: Pointer to wpa_supplicant data
2283 * @bssid: BSSID to check
2284 * Returns: 0 if the BSSID is filtered or 1 if not
2285 *
2286 * This function is used to filter out specific BSSIDs from scan reslts mainly
2287 * for testing purposes (SET bssid_filter ctrl_iface command).
2288 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002289int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
2290 const u8 *bssid)
2291{
2292 size_t i;
2293
2294 if (wpa_s->bssid_filter == NULL)
2295 return 1;
2296
2297 for (i = 0; i < wpa_s->bssid_filter_count; i++) {
2298 if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
2299 ETH_ALEN) == 0)
2300 return 1;
2301 }
2302
2303 return 0;
2304}
2305
2306
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002307void filter_scan_res(struct wpa_supplicant *wpa_s,
2308 struct wpa_scan_results *res)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002309{
2310 size_t i, j;
2311
2312 if (wpa_s->bssid_filter == NULL)
2313 return;
2314
2315 for (i = 0, j = 0; i < res->num; i++) {
2316 if (wpa_supplicant_filter_bssid_match(wpa_s,
2317 res->res[i]->bssid)) {
2318 res->res[j++] = res->res[i];
2319 } else {
2320 os_free(res->res[i]);
2321 res->res[i] = NULL;
2322 }
2323 }
2324
2325 if (res->num != j) {
2326 wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
2327 (int) (res->num - j));
2328 res->num = j;
2329 }
2330}
2331
2332
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002333void scan_snr(struct wpa_scan_res *res)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002334{
2335 if (res->flags & WPA_SCAN_NOISE_INVALID) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002336 res->noise = is_6ghz_freq(res->freq) ?
2337 DEFAULT_NOISE_FLOOR_6GHZ :
2338 (IS_5GHZ(res->freq) ?
2339 DEFAULT_NOISE_FLOOR_5GHZ : DEFAULT_NOISE_FLOOR_2GHZ);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002340 }
2341
2342 if (res->flags & WPA_SCAN_LEVEL_DBM) {
2343 res->snr = res->level - res->noise;
2344 } else {
2345 /* Level is not in dBm, so we can't calculate
2346 * SNR. Just use raw level (units unknown). */
2347 res->snr = res->level;
2348 }
2349}
2350
2351
Hai Shalom899fcc72020-10-19 14:38:18 -07002352/* Minimum SNR required to achieve a certain bitrate. */
2353struct minsnr_bitrate_entry {
2354 int minsnr;
2355 unsigned int bitrate; /* in Mbps */
2356};
2357
2358/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
2359static const int vht_mcs = 8;
2360
2361static const struct minsnr_bitrate_entry vht20_table[] = {
2362 { 0, 0 },
2363 { 2, 6500 }, /* HT20 MCS0 */
2364 { 5, 13000 }, /* HT20 MCS1 */
2365 { 9, 19500 }, /* HT20 MCS2 */
2366 { 11, 26000 }, /* HT20 MCS3 */
2367 { 15, 39000 }, /* HT20 MCS4 */
2368 { 18, 52000 }, /* HT20 MCS5 */
2369 { 20, 58500 }, /* HT20 MCS6 */
2370 { 25, 65000 }, /* HT20 MCS7 */
2371 { 29, 78000 }, /* VHT20 MCS8 */
2372 { -1, 78000 } /* SNR > 29 */
2373};
2374
2375static const struct minsnr_bitrate_entry vht40_table[] = {
2376 { 0, 0 },
2377 { 5, 13500 }, /* HT40 MCS0 */
2378 { 8, 27000 }, /* HT40 MCS1 */
2379 { 12, 40500 }, /* HT40 MCS2 */
2380 { 14, 54000 }, /* HT40 MCS3 */
2381 { 18, 81000 }, /* HT40 MCS4 */
2382 { 21, 108000 }, /* HT40 MCS5 */
2383 { 23, 121500 }, /* HT40 MCS6 */
2384 { 28, 135000 }, /* HT40 MCS7 */
2385 { 32, 162000 }, /* VHT40 MCS8 */
2386 { 34, 180000 }, /* VHT40 MCS9 */
2387 { -1, 180000 } /* SNR > 34 */
2388};
2389
2390static const struct minsnr_bitrate_entry vht80_table[] = {
2391 { 0, 0 },
2392 { 8, 29300 }, /* VHT80 MCS0 */
2393 { 11, 58500 }, /* VHT80 MCS1 */
2394 { 15, 87800 }, /* VHT80 MCS2 */
2395 { 17, 117000 }, /* VHT80 MCS3 */
2396 { 21, 175500 }, /* VHT80 MCS4 */
2397 { 24, 234000 }, /* VHT80 MCS5 */
2398 { 26, 263300 }, /* VHT80 MCS6 */
2399 { 31, 292500 }, /* VHT80 MCS7 */
2400 { 35, 351000 }, /* VHT80 MCS8 */
2401 { 37, 390000 }, /* VHT80 MCS9 */
2402 { -1, 390000 } /* SNR > 37 */
2403};
2404
2405
Hai Shaloma20dcd72022-02-04 13:43:00 -08002406static const struct minsnr_bitrate_entry vht160_table[] = {
2407 { 0, 0 },
2408 { 11, 58500 }, /* VHT160 MCS0 */
2409 { 14, 117000 }, /* VHT160 MCS1 */
2410 { 18, 175500 }, /* VHT160 MCS2 */
2411 { 20, 234000 }, /* VHT160 MCS3 */
2412 { 24, 351000 }, /* VHT160 MCS4 */
2413 { 27, 468000 }, /* VHT160 MCS5 */
2414 { 29, 526500 }, /* VHT160 MCS6 */
2415 { 34, 585000 }, /* VHT160 MCS7 */
2416 { 38, 702000 }, /* VHT160 MCS8 */
2417 { 40, 780000 }, /* VHT160 MCS9 */
2418 { -1, 780000 } /* SNR > 37 */
2419};
2420
2421
2422static const struct minsnr_bitrate_entry he20_table[] = {
2423 { 0, 0 },
2424 { 2, 8600 }, /* HE20 MCS0 */
2425 { 5, 17200 }, /* HE20 MCS1 */
2426 { 9, 25800 }, /* HE20 MCS2 */
2427 { 11, 34400 }, /* HE20 MCS3 */
2428 { 15, 51600 }, /* HE20 MCS4 */
2429 { 18, 68800 }, /* HE20 MCS5 */
2430 { 20, 77400 }, /* HE20 MCS6 */
2431 { 25, 86000 }, /* HE20 MCS7 */
2432 { 29, 103200 }, /* HE20 MCS8 */
2433 { 31, 114700 }, /* HE20 MCS9 */
2434 { 34, 129000 }, /* HE20 MCS10 */
2435 { 36, 143400 }, /* HE20 MCS11 */
2436 { -1, 143400 } /* SNR > 29 */
2437};
2438
2439static const struct minsnr_bitrate_entry he40_table[] = {
2440 { 0, 0 },
2441 { 5, 17200 }, /* HE40 MCS0 */
2442 { 8, 34400 }, /* HE40 MCS1 */
2443 { 12, 51600 }, /* HE40 MCS2 */
2444 { 14, 68800 }, /* HE40 MCS3 */
2445 { 18, 103200 }, /* HE40 MCS4 */
2446 { 21, 137600 }, /* HE40 MCS5 */
2447 { 23, 154900 }, /* HE40 MCS6 */
2448 { 28, 172100 }, /* HE40 MCS7 */
2449 { 32, 206500 }, /* HE40 MCS8 */
2450 { 34, 229400 }, /* HE40 MCS9 */
2451 { 37, 258100 }, /* HE40 MCS10 */
2452 { 39, 286800 }, /* HE40 MCS11 */
2453 { -1, 286800 } /* SNR > 34 */
2454};
2455
2456static const struct minsnr_bitrate_entry he80_table[] = {
2457 { 0, 0 },
2458 { 8, 36000 }, /* HE80 MCS0 */
2459 { 11, 72100 }, /* HE80 MCS1 */
2460 { 15, 108100 }, /* HE80 MCS2 */
2461 { 17, 144100 }, /* HE80 MCS3 */
2462 { 21, 216200 }, /* HE80 MCS4 */
2463 { 24, 288200 }, /* HE80 MCS5 */
2464 { 26, 324300 }, /* HE80 MCS6 */
2465 { 31, 360300 }, /* HE80 MCS7 */
2466 { 35, 432400 }, /* HE80 MCS8 */
2467 { 37, 480400 }, /* HE80 MCS9 */
2468 { 40, 540400 }, /* HE80 MCS10 */
2469 { 42, 600500 }, /* HE80 MCS11 */
2470 { -1, 600500 } /* SNR > 37 */
2471};
2472
2473
2474static const struct minsnr_bitrate_entry he160_table[] = {
2475 { 0, 0 },
2476 { 11, 72100 }, /* HE160 MCS0 */
2477 { 14, 144100 }, /* HE160 MCS1 */
2478 { 18, 216200 }, /* HE160 MCS2 */
2479 { 20, 288200 }, /* HE160 MCS3 */
2480 { 24, 432400 }, /* HE160 MCS4 */
2481 { 27, 576500 }, /* HE160 MCS5 */
2482 { 29, 648500 }, /* HE160 MCS6 */
2483 { 34, 720600 }, /* HE160 MCS7 */
2484 { 38, 864700 }, /* HE160 MCS8 */
2485 { 40, 960800 }, /* HE160 MCS9 */
2486 { 43, 1080900 }, /* HE160 MCS10 */
2487 { 45, 1201000 }, /* HE160 MCS11 */
2488 { -1, 1201000 } /* SNR > 37 */
2489};
2490
2491
Hai Shalomfdcde762020-04-02 11:19:20 -07002492static unsigned int interpolate_rate(int snr, int snr0, int snr1,
2493 int rate0, int rate1)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002494{
Hai Shalomfdcde762020-04-02 11:19:20 -07002495 return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002496}
2497
2498
Hai Shalom899fcc72020-10-19 14:38:18 -07002499static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
2500 int snr, bool vht)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002501{
Hai Shalom899fcc72020-10-19 14:38:18 -07002502 const struct minsnr_bitrate_entry *prev, *entry = table;
2503
2504 while ((entry->minsnr != -1) &&
2505 (snr >= entry->minsnr) &&
2506 (vht || entry - table <= vht_mcs))
2507 entry++;
2508 if (entry == table)
2509 return entry->bitrate;
2510 prev = entry - 1;
2511 if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
2512 return prev->bitrate;
2513 return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
2514 entry->bitrate);
Hai Shalomfdcde762020-04-02 11:19:20 -07002515}
2516
2517
Hai Shalom899fcc72020-10-19 14:38:18 -07002518static unsigned int max_ht20_rate(int snr, bool vht)
Hai Shalomfdcde762020-04-02 11:19:20 -07002519{
Hai Shalom899fcc72020-10-19 14:38:18 -07002520 return max_rate(vht20_table, snr, vht);
2521}
2522
2523
2524static unsigned int max_ht40_rate(int snr, bool vht)
2525{
2526 return max_rate(vht40_table, snr, vht);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002527}
2528
2529
2530static unsigned int max_vht80_rate(int snr)
2531{
Hai Shalom899fcc72020-10-19 14:38:18 -07002532 return max_rate(vht80_table, snr, 1);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002533}
2534
Hai Shalomfdcde762020-04-02 11:19:20 -07002535
Hai Shaloma20dcd72022-02-04 13:43:00 -08002536static unsigned int max_vht160_rate(int snr)
2537{
2538 return max_rate(vht160_table, snr, 1);
2539}
2540
2541
2542static unsigned int max_he_rate(const struct minsnr_bitrate_entry table[],
2543 int snr)
2544{
2545 const struct minsnr_bitrate_entry *prev, *entry = table;
2546
2547 while (entry->minsnr != -1 && snr >= entry->minsnr)
2548 entry++;
2549 if (entry == table)
2550 return 0;
2551 prev = entry - 1;
2552 if (entry->minsnr == -1)
2553 return prev->bitrate;
2554 return interpolate_rate(snr, prev->minsnr, entry->minsnr,
2555 prev->bitrate, entry->bitrate);
2556}
2557
2558
Hai Shalomfdcde762020-04-02 11:19:20 -07002559unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
2560 const u8 *ies, size_t ies_len, int rate,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002561 int snr, int freq)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002562{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002563 struct hostapd_hw_modes *hw_mode;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002564 unsigned int est, tmp;
Hai Shalomfdcde762020-04-02 11:19:20 -07002565 const u8 *ie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002566
2567 /* Limit based on estimated SNR */
2568 if (rate > 1 * 2 && snr < 1)
2569 rate = 1 * 2;
2570 else if (rate > 2 * 2 && snr < 4)
2571 rate = 2 * 2;
2572 else if (rate > 6 * 2 && snr < 5)
2573 rate = 6 * 2;
2574 else if (rate > 9 * 2 && snr < 6)
2575 rate = 9 * 2;
2576 else if (rate > 12 * 2 && snr < 7)
2577 rate = 12 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002578 else if (rate > 12 * 2 && snr < 8)
2579 rate = 14 * 2;
2580 else if (rate > 12 * 2 && snr < 9)
2581 rate = 16 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002582 else if (rate > 18 * 2 && snr < 10)
2583 rate = 18 * 2;
2584 else if (rate > 24 * 2 && snr < 11)
2585 rate = 24 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002586 else if (rate > 24 * 2 && snr < 12)
2587 rate = 27 * 2;
2588 else if (rate > 24 * 2 && snr < 13)
2589 rate = 30 * 2;
2590 else if (rate > 24 * 2 && snr < 14)
2591 rate = 33 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002592 else if (rate > 36 * 2 && snr < 15)
2593 rate = 36 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002594 else if (rate > 36 * 2 && snr < 16)
2595 rate = 39 * 2;
2596 else if (rate > 36 * 2 && snr < 17)
2597 rate = 42 * 2;
2598 else if (rate > 36 * 2 && snr < 18)
2599 rate = 45 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002600 else if (rate > 48 * 2 && snr < 19)
2601 rate = 48 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002602 else if (rate > 48 * 2 && snr < 20)
2603 rate = 51 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002604 else if (rate > 54 * 2 && snr < 21)
2605 rate = 54 * 2;
2606 est = rate * 500;
2607
Hai Shaloma20dcd72022-02-04 13:43:00 -08002608 hw_mode = get_mode_with_freq(wpa_s->hw.modes, wpa_s->hw.num_modes,
2609 freq);
2610
2611 if (hw_mode && hw_mode->ht_capab) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002612 ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002613 if (ie) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002614 tmp = max_ht20_rate(snr, false);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002615 if (tmp > est)
2616 est = tmp;
2617 }
2618 }
2619
Hai Shaloma20dcd72022-02-04 13:43:00 -08002620 if (hw_mode &&
2621 (hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002622 ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002623 if (ie && ie[1] >= 2 &&
2624 (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002625 tmp = max_ht40_rate(snr, false);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002626 if (tmp > est)
2627 est = tmp;
2628 }
2629 }
2630
Hai Shaloma20dcd72022-02-04 13:43:00 -08002631 if (hw_mode && hw_mode->vht_capab) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002632 /* Use +1 to assume VHT is always faster than HT */
Hai Shalomfdcde762020-04-02 11:19:20 -07002633 ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002634 if (ie) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002635 bool vht80 = false, vht160 = false;
2636
Hai Shalom899fcc72020-10-19 14:38:18 -07002637 tmp = max_ht20_rate(snr, true) + 1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002638 if (tmp > est)
2639 est = tmp;
2640
Hai Shalomfdcde762020-04-02 11:19:20 -07002641 ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002642 if (ie && ie[1] >= 2 &&
2643 (ie[3] &
2644 HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002645 tmp = max_ht40_rate(snr, true) + 1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002646 if (tmp > est)
2647 est = tmp;
2648 }
2649
Hai Shaloma20dcd72022-02-04 13:43:00 -08002650 /* Determine VHT BSS bandwidth based on IEEE Std
2651 * 802.11-2020, Table 11-23 (VHT BSs bandwidth) */
Hai Shalomfdcde762020-04-02 11:19:20 -07002652 ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002653 if (ie && ie[1] >= 3) {
2654 u8 cw = ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK;
2655 u8 seg0 = ie[3];
2656 u8 seg1 = ie[4];
2657
2658 if (cw)
2659 vht80 = true;
2660 if (cw == 2 ||
2661 (cw == 3 &&
2662 (seg1 > 0 && abs(seg1 - seg0) == 16)))
2663 vht160 = true;
2664 if (cw == 1 &&
2665 ((seg1 > 0 && abs(seg1 - seg0) == 8) ||
2666 (seg1 > 0 && abs(seg1 - seg0) == 16)))
2667 vht160 = true;
2668 }
2669
2670 if (vht80) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002671 tmp = max_vht80_rate(snr) + 1;
2672 if (tmp > est)
2673 est = tmp;
2674 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002675
2676 if (vht160 &&
2677 (hw_mode->vht_capab &
2678 (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
2679 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
2680 tmp = max_vht160_rate(snr) + 1;
2681 if (tmp > est)
2682 est = tmp;
2683 }
2684 }
2685 }
2686
2687 if (hw_mode && hw_mode->he_capab[IEEE80211_MODE_INFRA].he_supported) {
2688 /* Use +2 to assume HE is always faster than HT/VHT */
2689 struct ieee80211_he_capabilities *he;
2690 struct he_capabilities *own_he;
2691 u8 cw;
2692
2693 ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES);
2694 if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN))
2695 return est;
2696 he = (struct ieee80211_he_capabilities *) &ie[3];
2697 own_he = &hw_mode->he_capab[IEEE80211_MODE_INFRA];
2698
2699 tmp = max_he_rate(he20_table, snr) + 2;
2700 if (tmp > est)
2701 est = tmp;
2702
2703 cw = he->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
2704 own_he->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
2705 if (cw &
2706 (IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G :
2707 HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
2708 tmp = max_he_rate(he40_table, snr) + 2;
2709 if (tmp > est)
2710 est = tmp;
2711 }
2712
2713 if (!IS_2P4GHZ(freq) &&
2714 (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
2715 tmp = max_he_rate(he80_table, snr) + 2;
2716 if (tmp > est)
2717 est = tmp;
2718 }
2719
2720 if (!IS_2P4GHZ(freq) &&
2721 (cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
2722 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) {
2723 tmp = max_he_rate(he160_table, snr) + 2;
2724 if (tmp > est)
2725 est = tmp;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002726 }
2727 }
2728
Hai Shalomfdcde762020-04-02 11:19:20 -07002729 return est;
2730}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002731
Hai Shalomfdcde762020-04-02 11:19:20 -07002732
2733void scan_est_throughput(struct wpa_supplicant *wpa_s,
2734 struct wpa_scan_res *res)
2735{
2736 int rate; /* max legacy rate in 500 kb/s units */
2737 int snr = res->snr;
2738 const u8 *ies = (const void *) (res + 1);
2739 size_t ie_len = res->ie_len;
2740
2741 if (res->est_throughput)
2742 return;
2743
2744 /* Get maximum legacy rate */
2745 rate = wpa_scan_get_max_rate(res);
2746
2747 if (!ie_len)
2748 ie_len = res->beacon_ie_len;
2749 res->est_throughput =
Hai Shaloma20dcd72022-02-04 13:43:00 -08002750 wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, res->freq);
Hai Shalomfdcde762020-04-02 11:19:20 -07002751
2752 /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002753}
2754
2755
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002756/**
2757 * wpa_supplicant_get_scan_results - Get scan results
2758 * @wpa_s: Pointer to wpa_supplicant data
2759 * @info: Information about what was scanned or %NULL if not available
2760 * @new_scan: Whether a new scan was performed
2761 * Returns: Scan results, %NULL on failure
2762 *
2763 * This function request the current scan results from the driver and updates
2764 * the local BSS list wpa_s->bss. The caller is responsible for freeing the
2765 * results with wpa_scan_results_free().
2766 */
2767struct wpa_scan_results *
2768wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
2769 struct scan_info *info, int new_scan)
2770{
2771 struct wpa_scan_results *scan_res;
2772 size_t i;
2773 int (*compar)(const void *, const void *) = wpa_scan_result_compar;
2774
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002775 scan_res = wpa_drv_get_scan_results2(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002776 if (scan_res == NULL) {
2777 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
2778 return NULL;
2779 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002780 if (scan_res->fetch_time.sec == 0) {
2781 /*
2782 * Make sure we have a valid timestamp if the driver wrapper
2783 * does not set this.
2784 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002785 os_get_reltime(&scan_res->fetch_time);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002786 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002787 filter_scan_res(wpa_s, scan_res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002788
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002789 for (i = 0; i < scan_res->num; i++) {
2790 struct wpa_scan_res *scan_res_item = scan_res->res[i];
2791
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002792 scan_snr(scan_res_item);
2793 scan_est_throughput(wpa_s, scan_res_item);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002794 }
2795
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002796#ifdef CONFIG_WPS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002797 if (wpas_wps_searching(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002798 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
2799 "provisioning rules");
2800 compar = wpa_scan_result_wps_compar;
2801 }
2802#endif /* CONFIG_WPS */
2803
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002804 if (scan_res->res) {
2805 qsort(scan_res->res, scan_res->num,
2806 sizeof(struct wpa_scan_res *), compar);
2807 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002808 dump_scan_res(scan_res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002809
Dmitry Shmidt29333592017-01-09 12:27:11 -08002810 if (wpa_s->ignore_post_flush_scan_res) {
2811 /* FLUSH command aborted an ongoing scan and these are the
2812 * results from the aborted scan. Do not process the results to
2813 * maintain flushed state. */
2814 wpa_dbg(wpa_s, MSG_DEBUG,
2815 "Do not update BSS table based on pending post-FLUSH scan results");
2816 wpa_s->ignore_post_flush_scan_res = 0;
2817 return scan_res;
2818 }
2819
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002820 wpa_bss_update_start(wpa_s);
2821 for (i = 0; i < scan_res->num; i++)
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002822 wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
2823 &scan_res->fetch_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002824 wpa_bss_update_end(wpa_s, info, new_scan);
2825
2826 return scan_res;
2827}
2828
2829
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002830/**
2831 * wpa_supplicant_update_scan_results - Update scan results from the driver
2832 * @wpa_s: Pointer to wpa_supplicant data
2833 * Returns: 0 on success, -1 on failure
2834 *
2835 * This function updates the BSS table within wpa_supplicant based on the
2836 * currently available scan results from the driver without requesting a new
2837 * scan. This is used in cases where the driver indicates an association
2838 * (including roaming within ESS) and wpa_supplicant does not yet have the
2839 * needed information to complete the connection (e.g., to perform validation
2840 * steps in 4-way handshake).
2841 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002842int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
2843{
2844 struct wpa_scan_results *scan_res;
2845 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
2846 if (scan_res == NULL)
2847 return -1;
2848 wpa_scan_results_free(scan_res);
2849
2850 return 0;
2851}
Dmitry Shmidt3a787e62013-01-17 10:32:35 -08002852
2853
2854/**
2855 * scan_only_handler - Reports scan results
2856 */
2857void scan_only_handler(struct wpa_supplicant *wpa_s,
2858 struct wpa_scan_results *scan_res)
2859{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002860 wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002861 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
2862 wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
2863 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
2864 wpa_s->manual_scan_id);
2865 wpa_s->manual_scan_use_id = 0;
2866 } else {
2867 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
2868 }
Dmitry Shmidt3a787e62013-01-17 10:32:35 -08002869 wpas_notify_scan_results(wpa_s);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002870 wpas_notify_scan_done(wpa_s, 1);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002871 if (wpa_s->scan_work) {
2872 struct wpa_radio_work *work = wpa_s->scan_work;
2873 wpa_s->scan_work = NULL;
2874 radio_work_done(work);
2875 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002876
2877 if (wpa_s->wpa_state == WPA_SCANNING)
2878 wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
Dmitry Shmidt3a787e62013-01-17 10:32:35 -08002879}
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -07002880
2881
2882int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
2883{
2884 return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
2885}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002886
2887
2888struct wpa_driver_scan_params *
2889wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
2890{
2891 struct wpa_driver_scan_params *params;
2892 size_t i;
2893 u8 *n;
2894
2895 params = os_zalloc(sizeof(*params));
2896 if (params == NULL)
2897 return NULL;
2898
2899 for (i = 0; i < src->num_ssids; i++) {
2900 if (src->ssids[i].ssid) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002901 n = os_memdup(src->ssids[i].ssid,
2902 src->ssids[i].ssid_len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002903 if (n == NULL)
2904 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002905 params->ssids[i].ssid = n;
2906 params->ssids[i].ssid_len = src->ssids[i].ssid_len;
2907 }
2908 }
2909 params->num_ssids = src->num_ssids;
2910
2911 if (src->extra_ies) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002912 n = os_memdup(src->extra_ies, src->extra_ies_len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002913 if (n == NULL)
2914 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002915 params->extra_ies = n;
2916 params->extra_ies_len = src->extra_ies_len;
2917 }
2918
2919 if (src->freqs) {
2920 int len = int_array_len(src->freqs);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002921 params->freqs = os_memdup(src->freqs, (len + 1) * sizeof(int));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002922 if (params->freqs == NULL)
2923 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002924 }
2925
2926 if (src->filter_ssids) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002927 params->filter_ssids = os_memdup(src->filter_ssids,
2928 sizeof(*params->filter_ssids) *
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002929 src->num_filter_ssids);
2930 if (params->filter_ssids == NULL)
2931 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002932 params->num_filter_ssids = src->num_filter_ssids;
2933 }
2934
2935 params->filter_rssi = src->filter_rssi;
2936 params->p2p_probe = src->p2p_probe;
2937 params->only_new_results = src->only_new_results;
Dmitry Shmidt2271d3f2014-06-23 12:16:31 -07002938 params->low_priority = src->low_priority;
Dmitry Shmidt29333592017-01-09 12:27:11 -08002939 params->duration = src->duration;
2940 params->duration_mandatory = src->duration_mandatory;
Hai Shalomce48b4a2018-09-05 11:41:35 -07002941 params->oce_scan = src->oce_scan;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002942
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002943 if (src->sched_scan_plans_num > 0) {
2944 params->sched_scan_plans =
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002945 os_memdup(src->sched_scan_plans,
2946 sizeof(*src->sched_scan_plans) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002947 src->sched_scan_plans_num);
2948 if (!params->sched_scan_plans)
2949 goto failed;
2950
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002951 params->sched_scan_plans_num = src->sched_scan_plans_num;
2952 }
2953
Hai Shalomc3565922019-10-28 11:58:20 -07002954 if (src->mac_addr_rand &&
2955 wpa_setup_mac_addr_rand_params(params, src->mac_addr))
2956 goto failed;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08002957
2958 if (src->bssid) {
2959 u8 *bssid;
2960
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002961 bssid = os_memdup(src->bssid, ETH_ALEN);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08002962 if (!bssid)
2963 goto failed;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08002964 params->bssid = bssid;
2965 }
2966
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002967 params->relative_rssi_set = src->relative_rssi_set;
2968 params->relative_rssi = src->relative_rssi;
2969 params->relative_adjust_band = src->relative_adjust_band;
2970 params->relative_adjust_rssi = src->relative_adjust_rssi;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002971 params->p2p_include_6ghz = src->p2p_include_6ghz;
Sunil8cd6f4d2022-06-28 18:40:46 +00002972 params->non_coloc_6ghz = src->non_coloc_6ghz;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002973 return params;
2974
2975failed:
2976 wpa_scan_free_params(params);
2977 return NULL;
2978}
2979
2980
2981void wpa_scan_free_params(struct wpa_driver_scan_params *params)
2982{
2983 size_t i;
2984
2985 if (params == NULL)
2986 return;
2987
2988 for (i = 0; i < params->num_ssids; i++)
2989 os_free((u8 *) params->ssids[i].ssid);
2990 os_free((u8 *) params->extra_ies);
2991 os_free(params->freqs);
2992 os_free(params->filter_ssids);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002993 os_free(params->sched_scan_plans);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002994
2995 /*
2996 * Note: params->mac_addr_mask points to same memory allocation and
2997 * must not be freed separately.
2998 */
2999 os_free((u8 *) params->mac_addr);
3000
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003001 os_free((u8 *) params->bssid);
3002
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003003 os_free(params);
3004}
Dmitry Shmidt98660862014-03-11 17:26:21 -07003005
3006
3007int wpas_start_pno(struct wpa_supplicant *wpa_s)
3008{
Hai Shalomfdcde762020-04-02 11:19:20 -07003009 int ret;
3010 size_t prio, i, num_ssid, num_match_ssid;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003011 struct wpa_ssid *ssid;
3012 struct wpa_driver_scan_params params;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003013 struct sched_scan_plan scan_plan;
Dmitry Shmidte4663042016-04-04 10:07:49 -07003014 unsigned int max_sched_scan_ssids;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003015
3016 if (!wpa_s->sched_scan_supported)
3017 return -1;
3018
Dmitry Shmidte4663042016-04-04 10:07:49 -07003019 if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
3020 max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
3021 else
3022 max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
3023 if (max_sched_scan_ssids < 1)
3024 return -1;
3025
Dmitry Shmidt98660862014-03-11 17:26:21 -07003026 if (wpa_s->pno || wpa_s->pno_sched_pending)
3027 return 0;
3028
3029 if ((wpa_s->wpa_state > WPA_SCANNING) &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003030 (wpa_s->wpa_state < WPA_COMPLETED)) {
Dmitry Shmidt98660862014-03-11 17:26:21 -07003031 wpa_printf(MSG_ERROR, "PNO: In assoc process");
3032 return -EAGAIN;
3033 }
3034
3035 if (wpa_s->wpa_state == WPA_SCANNING) {
3036 wpa_supplicant_cancel_scan(wpa_s);
3037 if (wpa_s->sched_scanning) {
3038 wpa_printf(MSG_DEBUG, "Schedule PNO on completion of "
3039 "ongoing sched scan");
3040 wpa_supplicant_cancel_sched_scan(wpa_s);
3041 wpa_s->pno_sched_pending = 1;
3042 return 0;
3043 }
3044 }
3045
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003046 if (wpa_s->sched_scan_stop_req) {
3047 wpa_printf(MSG_DEBUG,
3048 "Schedule PNO after previous sched scan has stopped");
3049 wpa_s->pno_sched_pending = 1;
3050 return 0;
3051 }
3052
Dmitry Shmidt98660862014-03-11 17:26:21 -07003053 os_memset(&params, 0, sizeof(params));
3054
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003055 num_ssid = num_match_ssid = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003056 ssid = wpa_s->conf->ssid;
3057 while (ssid) {
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003058 if (!wpas_network_disabled(wpa_s, ssid)) {
3059 num_match_ssid++;
3060 if (ssid->scan_ssid)
3061 num_ssid++;
3062 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003063 ssid = ssid->next;
3064 }
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003065
3066 if (num_match_ssid == 0) {
3067 wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
3068 return -1;
3069 }
3070
3071 if (num_match_ssid > num_ssid) {
3072 params.num_ssids++; /* wildcard */
3073 num_ssid++;
3074 }
3075
Dmitry Shmidte4663042016-04-04 10:07:49 -07003076 if (num_ssid > max_sched_scan_ssids) {
Dmitry Shmidt98660862014-03-11 17:26:21 -07003077 wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
Dmitry Shmidte4663042016-04-04 10:07:49 -07003078 "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
3079 num_ssid = max_sched_scan_ssids;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003080 }
3081
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003082 if (num_match_ssid > wpa_s->max_match_sets) {
3083 num_match_ssid = wpa_s->max_match_sets;
3084 wpa_dbg(wpa_s, MSG_DEBUG, "PNO: Too many SSIDs to match");
Dmitry Shmidt98660862014-03-11 17:26:21 -07003085 }
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003086 params.filter_ssids = os_calloc(num_match_ssid,
3087 sizeof(struct wpa_driver_scan_filter));
Dmitry Shmidt98660862014-03-11 17:26:21 -07003088 if (params.filter_ssids == NULL)
3089 return -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003090
Dmitry Shmidt98660862014-03-11 17:26:21 -07003091 i = 0;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003092 prio = 0;
3093 ssid = wpa_s->conf->pssid[prio];
Dmitry Shmidt98660862014-03-11 17:26:21 -07003094 while (ssid) {
3095 if (!wpas_network_disabled(wpa_s, ssid)) {
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003096 if (ssid->scan_ssid && params.num_ssids < num_ssid) {
3097 params.ssids[params.num_ssids].ssid =
3098 ssid->ssid;
3099 params.ssids[params.num_ssids].ssid_len =
3100 ssid->ssid_len;
3101 params.num_ssids++;
3102 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003103 os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
3104 ssid->ssid_len);
3105 params.filter_ssids[i].ssid_len = ssid->ssid_len;
3106 params.num_filter_ssids++;
3107 i++;
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003108 if (i == num_match_ssid)
Dmitry Shmidt98660862014-03-11 17:26:21 -07003109 break;
3110 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003111 if (ssid->pnext)
3112 ssid = ssid->pnext;
3113 else if (prio + 1 == wpa_s->conf->num_prio)
3114 break;
3115 else
3116 ssid = wpa_s->conf->pssid[++prio];
Dmitry Shmidt98660862014-03-11 17:26:21 -07003117 }
3118
3119 if (wpa_s->conf->filter_rssi)
3120 params.filter_rssi = wpa_s->conf->filter_rssi;
3121
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003122 if (wpa_s->sched_scan_plans_num) {
3123 params.sched_scan_plans = wpa_s->sched_scan_plans;
3124 params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
3125 } else {
3126 /* Set one scan plan that will run infinitely */
3127 if (wpa_s->conf->sched_scan_interval)
3128 scan_plan.interval = wpa_s->conf->sched_scan_interval;
3129 else
3130 scan_plan.interval = 10;
3131
3132 scan_plan.iterations = 0;
3133 params.sched_scan_plans = &scan_plan;
3134 params.sched_scan_plans_num = 1;
3135 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003136
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003137 params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay;
3138
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07003139 if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) {
3140 wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels");
3141 params.freqs = wpa_s->manual_sched_scan_freqs;
3142 }
3143
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003144 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
Hai Shalomc3565922019-10-28 11:58:20 -07003145 wpa_s->wpa_state <= WPA_SCANNING)
3146 wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_pno);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003147
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003148 wpa_scan_set_relative_rssi_params(wpa_s, &params);
3149
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003150 ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
Dmitry Shmidt98660862014-03-11 17:26:21 -07003151 os_free(params.filter_ssids);
Hai Shalomc3565922019-10-28 11:58:20 -07003152 os_free(params.mac_addr);
Dmitry Shmidt98660862014-03-11 17:26:21 -07003153 if (ret == 0)
3154 wpa_s->pno = 1;
3155 else
3156 wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO");
3157 return ret;
3158}
3159
3160
3161int wpas_stop_pno(struct wpa_supplicant *wpa_s)
3162{
3163 int ret = 0;
3164
3165 if (!wpa_s->pno)
3166 return 0;
3167
3168 ret = wpa_supplicant_stop_sched_scan(wpa_s);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003169 wpa_s->sched_scan_stop_req = 1;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003170
3171 wpa_s->pno = 0;
3172 wpa_s->pno_sched_pending = 0;
3173
3174 if (wpa_s->wpa_state == WPA_SCANNING)
3175 wpa_supplicant_req_scan(wpa_s, 0, 0);
3176
3177 return ret;
3178}
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003179
3180
3181void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
3182 unsigned int type)
3183{
3184 type &= MAC_ADDR_RAND_ALL;
3185 wpa_s->mac_addr_rand_enable &= ~type;
3186
3187 if (type & MAC_ADDR_RAND_SCAN) {
3188 os_free(wpa_s->mac_addr_scan);
3189 wpa_s->mac_addr_scan = NULL;
3190 }
3191
3192 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
3193 os_free(wpa_s->mac_addr_sched_scan);
3194 wpa_s->mac_addr_sched_scan = NULL;
3195 }
3196
3197 if (type & MAC_ADDR_RAND_PNO) {
3198 os_free(wpa_s->mac_addr_pno);
3199 wpa_s->mac_addr_pno = NULL;
3200 }
3201}
3202
3203
3204int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
3205 unsigned int type, const u8 *addr,
3206 const u8 *mask)
3207{
3208 u8 *tmp = NULL;
3209
Hai Shalom74f70d42019-02-11 14:42:39 -08003210 if ((wpa_s->mac_addr_rand_supported & type) != type ) {
3211 wpa_printf(MSG_INFO,
3212 "scan: MAC randomization type %u != supported=%u",
3213 type, wpa_s->mac_addr_rand_supported);
3214 return -1;
3215 }
3216
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003217 wpas_mac_addr_rand_scan_clear(wpa_s, type);
3218
3219 if (addr) {
3220 tmp = os_malloc(2 * ETH_ALEN);
3221 if (!tmp)
3222 return -1;
3223 os_memcpy(tmp, addr, ETH_ALEN);
3224 os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN);
3225 }
3226
3227 if (type == MAC_ADDR_RAND_SCAN) {
3228 wpa_s->mac_addr_scan = tmp;
3229 } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
3230 wpa_s->mac_addr_sched_scan = tmp;
3231 } else if (type == MAC_ADDR_RAND_PNO) {
3232 wpa_s->mac_addr_pno = tmp;
3233 } else {
3234 wpa_printf(MSG_INFO,
3235 "scan: Invalid MAC randomization type=0x%x",
3236 type);
3237 os_free(tmp);
3238 return -1;
3239 }
3240
3241 wpa_s->mac_addr_rand_enable |= type;
3242 return 0;
3243}
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003244
3245
Hai Shalomc3565922019-10-28 11:58:20 -07003246int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
3247 unsigned int type, u8 *mask)
3248{
3249 const u8 *to_copy;
3250
3251 if ((wpa_s->mac_addr_rand_enable & type) != type)
3252 return -1;
3253
3254 if (type == MAC_ADDR_RAND_SCAN) {
3255 to_copy = wpa_s->mac_addr_scan;
3256 } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
3257 to_copy = wpa_s->mac_addr_sched_scan;
3258 } else if (type == MAC_ADDR_RAND_PNO) {
3259 to_copy = wpa_s->mac_addr_pno;
3260 } else {
3261 wpa_printf(MSG_DEBUG,
3262 "scan: Invalid MAC randomization type=0x%x",
3263 type);
3264 return -1;
3265 }
3266
3267 os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
3268 return 0;
3269}
3270
3271
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003272int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
3273{
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003274 struct wpa_radio_work *work;
3275 struct wpa_radio *radio = wpa_s->radio;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003276
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003277 dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
3278 if (work->wpa_s != wpa_s || !work->started ||
3279 (os_strcmp(work->type, "scan") != 0 &&
3280 os_strcmp(work->type, "p2p-scan") != 0))
3281 continue;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003282 wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003283 return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003284 }
3285
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003286 wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort");
3287 return -1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003288}
3289
3290
3291int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd)
3292{
3293 struct sched_scan_plan *scan_plans = NULL;
3294 const char *token, *context = NULL;
3295 unsigned int num = 0;
3296
3297 if (!cmd)
3298 return -1;
3299
3300 if (!cmd[0]) {
3301 wpa_printf(MSG_DEBUG, "Clear sched scan plans");
3302 os_free(wpa_s->sched_scan_plans);
3303 wpa_s->sched_scan_plans = NULL;
3304 wpa_s->sched_scan_plans_num = 0;
3305 return 0;
3306 }
3307
3308 while ((token = cstr_token(cmd, " ", &context))) {
3309 int ret;
3310 struct sched_scan_plan *scan_plan, *n;
3311
3312 n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans));
3313 if (!n)
3314 goto fail;
3315
3316 scan_plans = n;
3317 scan_plan = &scan_plans[num];
3318 num++;
3319
3320 ret = sscanf(token, "%u:%u", &scan_plan->interval,
3321 &scan_plan->iterations);
3322 if (ret <= 0 || ret > 2 || !scan_plan->interval) {
3323 wpa_printf(MSG_ERROR,
3324 "Invalid sched scan plan input: %s", token);
3325 goto fail;
3326 }
3327
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003328 if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
3329 wpa_printf(MSG_WARNING,
3330 "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
3331 num, scan_plan->interval,
3332 wpa_s->max_sched_scan_plan_interval);
3333 scan_plan->interval =
3334 wpa_s->max_sched_scan_plan_interval;
3335 }
3336
3337 if (ret == 1) {
3338 scan_plan->iterations = 0;
3339 break;
3340 }
3341
3342 if (!scan_plan->iterations) {
3343 wpa_printf(MSG_ERROR,
3344 "scan plan %u: Number of iterations cannot be zero",
3345 num);
3346 goto fail;
3347 }
3348
3349 if (scan_plan->iterations >
3350 wpa_s->max_sched_scan_plan_iterations) {
3351 wpa_printf(MSG_WARNING,
3352 "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)",
3353 num, scan_plan->iterations,
3354 wpa_s->max_sched_scan_plan_iterations);
3355 scan_plan->iterations =
3356 wpa_s->max_sched_scan_plan_iterations;
3357 }
3358
3359 wpa_printf(MSG_DEBUG,
3360 "scan plan %u: interval=%u iterations=%u",
3361 num, scan_plan->interval, scan_plan->iterations);
3362 }
3363
3364 if (!scan_plans) {
3365 wpa_printf(MSG_ERROR, "Invalid scan plans entry");
3366 goto fail;
3367 }
3368
3369 if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) {
3370 wpa_printf(MSG_ERROR,
3371 "All scan plans but the last must specify a number of iterations");
3372 goto fail;
3373 }
3374
3375 wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u",
3376 num, scan_plans[num - 1].interval);
3377
3378 if (num > wpa_s->max_sched_scan_plans) {
3379 wpa_printf(MSG_WARNING,
3380 "Too many scheduled scan plans (only %u supported)",
3381 wpa_s->max_sched_scan_plans);
3382 wpa_printf(MSG_WARNING,
3383 "Use only the first %u scan plans, and the last one (in infinite loop)",
3384 wpa_s->max_sched_scan_plans - 1);
3385 os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1],
3386 &scan_plans[num - 1], sizeof(*scan_plans));
3387 num = wpa_s->max_sched_scan_plans;
3388 }
3389
3390 os_free(wpa_s->sched_scan_plans);
3391 wpa_s->sched_scan_plans = scan_plans;
3392 wpa_s->sched_scan_plans_num = num;
3393
3394 return 0;
3395
3396fail:
3397 os_free(scan_plans);
3398 wpa_printf(MSG_ERROR, "invalid scan plans list");
3399 return -1;
3400}
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07003401
3402
3403/**
3404 * wpas_scan_reset_sched_scan - Reset sched_scan state
3405 * @wpa_s: Pointer to wpa_supplicant data
3406 *
3407 * This function is used to cancel a running scheduled scan and to reset an
3408 * internal scan state to continue with a regular scan on the following
3409 * wpa_supplicant_req_scan() calls.
3410 */
3411void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s)
3412{
3413 wpa_s->normal_scans = 0;
3414 if (wpa_s->sched_scanning) {
3415 wpa_s->sched_scan_timed_out = 0;
3416 wpa_s->prev_sched_ssid = NULL;
3417 wpa_supplicant_cancel_sched_scan(wpa_s);
3418 }
3419}
3420
3421
3422void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s)
3423{
3424 /* simulate timeout to restart the sched scan */
3425 wpa_s->sched_scan_timed_out = 1;
3426 wpa_s->prev_sched_ssid = NULL;
3427 wpa_supplicant_cancel_sched_scan(wpa_s);
3428}