blob: 3fd86be4d26e7d5054bfd9bca46a9241d5564baf [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
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000302 wpa_s->wps_scan_done = false;
303
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800304 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800305}
306
307
308static void
309wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
310{
311 struct wpa_supplicant *wpa_s = eloop_ctx;
312
313 wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan");
314
315 if (wpa_supplicant_req_sched_scan(wpa_s))
316 wpa_supplicant_req_scan(wpa_s, 0, 0);
317}
318
319
320static void
321wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
322{
323 struct wpa_supplicant *wpa_s = eloop_ctx;
324
325 wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it");
326
327 wpa_s->sched_scan_timed_out = 1;
328 wpa_supplicant_cancel_sched_scan(wpa_s);
329}
330
331
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700332static int
333wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
334 struct wpa_driver_scan_params *params)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800335{
336 int ret;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700337
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800338 wpa_supplicant_notify_scanning(wpa_s, 1);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800339 ret = wpa_drv_sched_scan(wpa_s, params);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800340 if (ret)
341 wpa_supplicant_notify_scanning(wpa_s, 0);
Dmitry Shmidtb96dad42013-11-05 10:07:29 -0800342 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800343 wpa_s->sched_scanning = 1;
344
345 return ret;
346}
347
348
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700349static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800350{
351 int ret;
352
353 ret = wpa_drv_stop_sched_scan(wpa_s);
354 if (ret) {
355 wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!");
356 /* TODO: what to do if stopping fails? */
357 return -1;
358 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359
360 return ret;
361}
362
363
364static struct wpa_driver_scan_filter *
365wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
366{
367 struct wpa_driver_scan_filter *ssids;
368 struct wpa_ssid *ssid;
369 size_t count;
370
371 *num_ssids = 0;
372 if (!conf->filter_ssids)
373 return NULL;
374
375 for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) {
376 if (ssid->ssid && ssid->ssid_len)
377 count++;
378 }
379 if (count == 0)
380 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800381 ssids = os_calloc(count, sizeof(struct wpa_driver_scan_filter));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382 if (ssids == NULL)
383 return NULL;
384
385 for (ssid = conf->ssid; ssid; ssid = ssid->next) {
386 if (!ssid->ssid || !ssid->ssid_len)
387 continue;
388 os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len);
389 ssids[*num_ssids].ssid_len = ssid->ssid_len;
390 (*num_ssids)++;
391 }
392
393 return ssids;
394}
395
396
Hai Shaloma20dcd72022-02-04 13:43:00 -0800397#ifdef CONFIG_P2P
398static bool is_6ghz_supported(struct wpa_supplicant *wpa_s)
399{
400 struct hostapd_channel_data *chnl;
401 int i, j;
402
403 for (i = 0; i < wpa_s->hw.num_modes; i++) {
404 if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) {
405 chnl = wpa_s->hw.modes[i].channels;
406 for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) {
407 if (chnl[j].flag & HOSTAPD_CHAN_DISABLED)
408 continue;
409 if (is_6ghz_freq(chnl[j].freq))
410 return true;
411 }
412 }
413 }
414
415 return false;
416}
417#endif /* CONFIG_P2P */
418
419
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800420static void wpa_supplicant_optimize_freqs(
421 struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
422{
423#ifdef CONFIG_P2P
424 if (params->freqs == NULL && wpa_s->p2p_in_provisioning &&
425 wpa_s->go_params) {
426 /* Optimize provisioning state scan based on GO information */
427 if (wpa_s->p2p_in_provisioning < 5 &&
428 wpa_s->go_params->freq > 0) {
429 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
430 "preferred frequency %d MHz",
431 wpa_s->go_params->freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800432 params->freqs = os_calloc(2, sizeof(int));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800433 if (params->freqs)
434 params->freqs[0] = wpa_s->go_params->freq;
435 } else if (wpa_s->p2p_in_provisioning < 8 &&
436 wpa_s->go_params->freq_list[0]) {
437 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
438 "channels");
439 int_array_concat(&params->freqs,
440 wpa_s->go_params->freq_list);
441 if (params->freqs)
442 int_array_sort_unique(params->freqs);
443 }
444 wpa_s->p2p_in_provisioning++;
445 }
Dmitry Shmidt15907092014-03-25 10:42:57 -0700446
447 if (params->freqs == NULL && wpa_s->p2p_in_invitation) {
448 /*
Matthew Wangdcf19452022-11-07 20:42:52 -0800449 * Perform a single-channel scan if the GO has already been
450 * discovered on another non-P2P interface. Note that a scan
451 * initiated by a P2P interface (e.g. the device interface)
452 * should already have sufficient IEs and scan results will be
453 * fetched on interface creation in that case.
454 */
455 if (wpa_s->p2p_in_invitation == 1 && wpa_s->current_ssid) {
456 struct wpa_supplicant *ifs;
457 struct wpa_bss *bss = NULL;
458 struct wpa_ssid *ssid = wpa_s->current_ssid;
459 u8 *bssid = ssid->bssid_set ? ssid->bssid : NULL;
460 dl_list_for_each(ifs, &wpa_s->radio->ifaces,
461 struct wpa_supplicant, radio_list) {
462 bss = wpa_bss_get(ifs, bssid, ssid->ssid,
463 ssid->ssid_len);
464 if (bss)
465 break;
466 }
467 if (bss && !disabled_freq(wpa_s, bss->freq)) {
468 params->freqs = os_calloc(2, sizeof(int));
Matthew Wangafc981e2023-03-17 21:30:12 +0000469 if (params->freqs) {
470 wpa_dbg(wpa_s, MSG_DEBUG,
471 "P2P: Scan only the known GO frequency %d MHz during invitation",
472 bss->freq);
Matthew Wangdcf19452022-11-07 20:42:52 -0800473 params->freqs[0] = bss->freq;
Matthew Wangafc981e2023-03-17 21:30:12 +0000474 }
Matthew Wangdcf19452022-11-07 20:42:52 -0800475 }
476 }
477 /*
Dmitry Shmidt15907092014-03-25 10:42:57 -0700478 * Optimize scan based on GO information during persistent
479 * group reinvocation
480 */
Matthew Wangafc981e2023-03-17 21:30:12 +0000481 if (!params->freqs && wpa_s->p2p_in_invitation < 5 &&
Dmitry Shmidt15907092014-03-25 10:42:57 -0700482 wpa_s->p2p_invite_go_freq > 0) {
Matthew Wang36173112022-11-07 21:48:44 -0800483 if (wpa_s->p2p_invite_go_freq == 2 ||
484 wpa_s->p2p_invite_go_freq == 5) {
Matthew Wang36173112022-11-07 21:48:44 -0800485 enum hostapd_hw_mode mode;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000486
487 wpa_dbg(wpa_s, MSG_DEBUG,
488 "P2P: Scan only GO preferred band %d GHz during invitation",
489 wpa_s->p2p_invite_go_freq);
490
491 if (!wpa_s->hw.modes)
Matthew Wang36173112022-11-07 21:48:44 -0800492 return;
493 mode = wpa_s->p2p_invite_go_freq == 5 ?
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000494 HOSTAPD_MODE_IEEE80211A :
495 HOSTAPD_MODE_IEEE80211G;
Matthew Wang36173112022-11-07 21:48:44 -0800496 if (wpa_s->p2p_in_invitation <= 2)
497 wpa_add_scan_freqs_list(wpa_s, mode,
498 params, false,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000499 false, true);
500 if (!params->freqs || params->freqs[0] == 0)
Matthew Wang36173112022-11-07 21:48:44 -0800501 wpa_add_scan_freqs_list(wpa_s, mode,
502 params, false,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000503 false, false);
Matthew Wang36173112022-11-07 21:48:44 -0800504 } else {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000505 wpa_dbg(wpa_s, MSG_DEBUG,
506 "P2P: Scan only GO preferred frequency %d MHz during invitation",
Matthew Wang36173112022-11-07 21:48:44 -0800507 wpa_s->p2p_invite_go_freq);
508 params->freqs = os_calloc(2, sizeof(int));
509 if (params->freqs)
510 params->freqs[0] =
511 wpa_s->p2p_invite_go_freq;
512 }
Dmitry Shmidt15907092014-03-25 10:42:57 -0700513 }
514 wpa_s->p2p_in_invitation++;
515 if (wpa_s->p2p_in_invitation > 20) {
516 /*
517 * This should not really happen since the variable is
518 * cleared on group removal, but if it does happen, make
519 * sure we do not get stuck in special invitation scan
520 * mode.
521 */
522 wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation");
523 wpa_s->p2p_in_invitation = 0;
Matthew Wang06b42472022-11-10 06:56:31 +0000524 wpa_s->p2p_retry_limit = 0;
Dmitry Shmidt15907092014-03-25 10:42:57 -0700525 }
526 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800527#endif /* CONFIG_P2P */
528
529#ifdef CONFIG_WPS
530 if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
531 /*
532 * Optimize post-provisioning scan based on channel used
533 * during provisioning.
534 */
535 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
536 "that was used during provisioning", wpa_s->wps_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800537 params->freqs = os_calloc(2, sizeof(int));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800538 if (params->freqs)
539 params->freqs[0] = wpa_s->wps_freq;
540 wpa_s->after_wps--;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800541 } else if (wpa_s->after_wps)
542 wpa_s->after_wps--;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800543
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800544 if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
545 {
546 /* Optimize provisioning scan based on already known channel */
547 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
548 wpa_s->wps_freq);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800549 params->freqs = os_calloc(2, sizeof(int));
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800550 if (params->freqs)
551 params->freqs[0] = wpa_s->wps_freq;
552 wpa_s->known_wps_freq = 0; /* only do this once */
553 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800554#endif /* CONFIG_WPS */
555}
556
557
558#ifdef CONFIG_INTERWORKING
559static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
560 struct wpabuf *buf)
561{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800562 wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
563 wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
564 1 + ETH_ALEN);
565 wpabuf_put_u8(buf, wpa_s->conf->access_network_type);
566 /* No Venue Info */
567 if (!is_zero_ether_addr(wpa_s->conf->hessid))
568 wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN);
569}
570#endif /* CONFIG_INTERWORKING */
571
572
Hai Shalomce48b4a2018-09-05 11:41:35 -0700573#ifdef CONFIG_MBO
574static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s,
575 struct wpabuf **ie)
576{
577 if (wpabuf_resize(ie, 5)) {
578 wpa_printf(MSG_DEBUG,
579 "Failed to allocate space for FILS Request Parameters element");
580 return;
581 }
582
583 /* FILS Request Parameters element */
584 wpabuf_put_u8(*ie, WLAN_EID_EXTENSION);
585 wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */
586 wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS);
587 /* Parameter control bitmap */
588 wpabuf_put_u8(*ie, 0);
589 /* Max Channel Time field - contains the value of MaxChannelTime
590 * parameter of the MLME-SCAN.request primitive represented in units of
591 * TUs, as an unsigned integer. A Max Channel Time field value of 255
592 * is used to indicate any duration of more than 254 TUs, or an
593 * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178)
594 */
595 wpabuf_put_u8(*ie, 255);
596}
597#endif /* CONFIG_MBO */
598
599
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700600void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
601{
602 struct wpabuf *default_ies = NULL;
603 u8 ext_capab[18];
Hai Shalom60840252021-02-19 19:02:11 -0800604 int ext_capab_len, frame_id;
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700605 enum wpa_driver_if_type type = WPA_IF_STATION;
606
607#ifdef CONFIG_P2P
608 if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
609 type = WPA_IF_P2P_CLIENT;
610#endif /* CONFIG_P2P */
611
612 wpa_drv_get_ext_capa(wpa_s, type);
613
614 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
615 sizeof(ext_capab));
616 if (ext_capab_len > 0 &&
617 wpabuf_resize(&default_ies, ext_capab_len) == 0)
618 wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
619
620#ifdef CONFIG_MBO
Hai Shalomce48b4a2018-09-05 11:41:35 -0700621 if (wpa_s->enable_oce & OCE_STA)
622 wpas_fils_req_param_add_max_channel(wpa_s, &default_ies);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700623 /* Send MBO and OCE capabilities */
624 if (wpabuf_resize(&default_ies, 12) == 0)
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700625 wpas_mbo_scan_ie(wpa_s, default_ies);
626#endif /* CONFIG_MBO */
627
Hai Shalom60840252021-02-19 19:02:11 -0800628 if (type == WPA_IF_P2P_CLIENT)
629 frame_id = VENDOR_ELEM_PROBE_REQ_P2P;
630 else
631 frame_id = VENDOR_ELEM_PROBE_REQ;
632
633 if (wpa_s->vendor_elem[frame_id]) {
634 size_t len;
635
636 len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
637 if (len > 0 && wpabuf_resize(&default_ies, len) == 0)
638 wpabuf_put_buf(default_ies,
639 wpa_s->vendor_elem[frame_id]);
640 }
641
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700642 if (default_ies)
643 wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
644 wpabuf_len(default_ies));
645 wpabuf_free(default_ies);
646}
647
648
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700649static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800650{
651 struct wpabuf *extra_ie = NULL;
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700652 u8 ext_capab[18];
653 int ext_capab_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800654#ifdef CONFIG_WPS
655 int wps = 0;
656 enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
657#endif /* CONFIG_WPS */
658
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -0700659#ifdef CONFIG_P2P
660 if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
661 wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
662 else
663#endif /* CONFIG_P2P */
664 wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
665
Dmitry Shmidtdda10c22015-03-24 16:05:01 -0700666 ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
667 sizeof(ext_capab));
668 if (ext_capab_len > 0 &&
669 wpabuf_resize(&extra_ie, ext_capab_len) == 0)
670 wpabuf_put_data(extra_ie, ext_capab, ext_capab_len);
671
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800672#ifdef CONFIG_INTERWORKING
673 if (wpa_s->conf->interworking &&
674 wpabuf_resize(&extra_ie, 100) == 0)
675 wpas_add_interworking_elements(wpa_s, extra_ie);
676#endif /* CONFIG_INTERWORKING */
677
Hai Shalomce48b4a2018-09-05 11:41:35 -0700678#ifdef CONFIG_MBO
679 if (wpa_s->enable_oce & OCE_STA)
680 wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie);
681#endif /* CONFIG_MBO */
682
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800683#ifdef CONFIG_WPS
684 wps = wpas_wps_in_use(wpa_s, &req_type);
685
686 if (wps) {
687 struct wpabuf *wps_ie;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700688 wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
689 DEV_PW_DEFAULT,
690 &wpa_s->wps->dev,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800691 wpa_s->wps->uuid, req_type,
692 0, NULL);
693 if (wps_ie) {
694 if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
695 wpabuf_put_buf(extra_ie, wps_ie);
696 wpabuf_free(wps_ie);
697 }
698 }
699
700#ifdef CONFIG_P2P
701 if (wps) {
702 size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
703 if (wpabuf_resize(&extra_ie, ielen) == 0)
704 wpas_p2p_scan_ie(wpa_s, extra_ie);
705 }
706#endif /* CONFIG_P2P */
707
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800708 wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
709
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800710#endif /* CONFIG_WPS */
711
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700712#ifdef CONFIG_HS20
Hai Shalom74f70d42019-02-11 14:42:39 -0800713 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0)
714 wpas_hs20_add_indication(extra_ie, -1, 0);
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -0700715#endif /* CONFIG_HS20 */
716
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800717#ifdef CONFIG_FST
718 if (wpa_s->fst_ies &&
719 wpabuf_resize(&extra_ie, wpabuf_len(wpa_s->fst_ies)) == 0)
720 wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
721#endif /* CONFIG_FST */
722
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800723#ifdef CONFIG_MBO
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700724 /* Send MBO and OCE capabilities */
725 if (wpabuf_resize(&extra_ie, 12) == 0)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800726 wpas_mbo_scan_ie(wpa_s, extra_ie);
727#endif /* CONFIG_MBO */
728
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700729 if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
730 struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
731
732 if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
733 wpabuf_put_buf(extra_ie, buf);
734 }
735
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800736 return extra_ie;
737}
738
739
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800740#ifdef CONFIG_P2P
741
742/*
743 * Check whether there are any enabled networks or credentials that could be
744 * used for a non-P2P connection.
745 */
746static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
747{
748 struct wpa_ssid *ssid;
749
750 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
751 if (wpas_network_disabled(wpa_s, ssid))
752 continue;
753 if (!ssid->p2p_group)
754 return 1;
755 }
756
757 if (wpa_s->conf->cred && wpa_s->conf->interworking &&
758 wpa_s->conf->auto_interworking)
759 return 1;
760
761 return 0;
762}
763
Dmitry Shmidtea69e842013-05-13 14:52:28 -0700764#endif /* CONFIG_P2P */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800765
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800766
Hai Shalom60840252021-02-19 19:02:11 -0800767int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
768 enum hostapd_hw_mode band,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000769 struct wpa_driver_scan_params *params,
770 bool is_6ghz, bool only_6ghz_psc,
Matthew Wang36173112022-11-07 21:48:44 -0800771 bool exclude_radar)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700772{
773 /* Include only supported channels for the specified band */
774 struct hostapd_hw_modes *mode;
Hai Shalom60840252021-02-19 19:02:11 -0800775 int num_chans = 0;
776 int *freqs, i;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700777
Hai Shalomfdcde762020-04-02 11:19:20 -0700778 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000779 if (!mode || !mode->num_channels)
Hai Shalom60840252021-02-19 19:02:11 -0800780 return -1;
781
782 if (params->freqs) {
783 while (params->freqs[num_chans])
784 num_chans++;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700785 }
786
Hai Shalom60840252021-02-19 19:02:11 -0800787 freqs = os_realloc(params->freqs,
788 (num_chans + mode->num_channels + 1) * sizeof(int));
789 if (!freqs)
790 return -1;
791
792 params->freqs = freqs;
793 for (i = 0; i < mode->num_channels; i++) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700794 if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
795 continue;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000796 if (exclude_radar &&
797 (mode->channels[i].flag & HOSTAPD_CHAN_RADAR))
Matthew Wang36173112022-11-07 21:48:44 -0800798 continue;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000799
800 if (is_6ghz && only_6ghz_psc &&
801 !is_6ghz_psc_frequency(mode->channels[i].freq))
802 continue;
803
Hai Shalom60840252021-02-19 19:02:11 -0800804 params->freqs[num_chans++] = mode->channels[i].freq;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700805 }
Hai Shalom60840252021-02-19 19:02:11 -0800806 params->freqs[num_chans] = 0;
807
808 return 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700809}
810
811
812static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
813 struct wpa_driver_scan_params *params)
814{
815 if (wpa_s->hw.modes == NULL)
816 return; /* unknown what channels the driver supports */
817 if (params->freqs)
818 return; /* already using a limited channel set */
Hai Shalom60840252021-02-19 19:02:11 -0800819
820 if (wpa_s->setband_mask & WPA_SETBAND_5G)
821 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000822 false, false, false);
Hai Shalom60840252021-02-19 19:02:11 -0800823 if (wpa_s->setband_mask & WPA_SETBAND_2G)
824 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000825 false, false, false);
Hai Shalom60840252021-02-19 19:02:11 -0800826 if (wpa_s->setband_mask & WPA_SETBAND_6G)
827 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000828 true, false, false);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700829}
830
831
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800832static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s,
833 struct wpa_driver_scan_params *params,
834 size_t max_ssids, const u8 *ssid, size_t ssid_len)
835{
836 unsigned int j;
837
838 for (j = 0; j < params->num_ssids; j++) {
839 if (params->ssids[j].ssid_len == ssid_len &&
840 params->ssids[j].ssid &&
841 os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0)
842 return; /* already in the list */
843 }
844
845 if (params->num_ssids + 1 > max_ssids) {
846 wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request");
847 return;
848 }
849
850 wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
851 wpa_ssid_txt(ssid, ssid_len));
852
853 params->ssids[params->num_ssids].ssid = ssid;
854 params->ssids[params->num_ssids].ssid_len = ssid_len;
855 params->num_ssids++;
856}
857
858
859static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
860 struct wpa_driver_scan_params *params,
861 struct wpa_ssid *ssid, size_t max_ssids)
862{
863#ifdef CONFIG_OWE
864 struct wpa_bss *bss;
865
866 if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE))
867 return;
868
869 wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s",
870 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
871
872 dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
873 const u8 *owe, *pos, *end;
874 const u8 *owe_ssid;
875 size_t owe_ssid_len;
876
877 if (bss->ssid_len != ssid->ssid_len ||
878 os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0)
879 continue;
880
881 owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
882 if (!owe || owe[1] < 4)
883 continue;
884
885 pos = owe + 6;
886 end = owe + 2 + owe[1];
887
888 /* Must include BSSID and ssid_len */
889 if (end - pos < ETH_ALEN + 1)
890 return;
891
892 /* Skip BSSID */
893 pos += ETH_ALEN;
894 owe_ssid_len = *pos++;
895 owe_ssid = pos;
896
897 if ((size_t) (end - pos) < owe_ssid_len ||
898 owe_ssid_len > SSID_MAX_LEN)
899 return;
900
901 wpa_printf(MSG_DEBUG,
902 "OWE: scan_ssids: transition mode OWE ssid=%s",
903 wpa_ssid_txt(owe_ssid, owe_ssid_len));
904
905 wpa_add_scan_ssid(wpa_s, params, max_ssids,
906 owe_ssid, owe_ssid_len);
907 return;
908 }
909#endif /* CONFIG_OWE */
910}
911
912
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700913static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
914 struct wpa_driver_scan_params *params,
915 size_t max_ssids)
916{
917 unsigned int i;
918 struct wpa_ssid *ssid;
919
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -0700920 /*
921 * For devices with max_ssids greater than 1, leave the last slot empty
922 * for adding the wildcard scan entry.
923 */
924 max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
925
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700926 for (i = 0; i < wpa_s->scan_id_count; i++) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700927 ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]);
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800928 if (!ssid)
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700929 continue;
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800930 if (ssid->scan_ssid)
931 wpa_add_scan_ssid(wpa_s, params, max_ssids,
932 ssid->ssid, ssid->ssid_len);
933 /*
934 * Also add the SSID of the OWE BSS, to allow discovery of
935 * transition mode APs more quickly.
936 */
937 wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids);
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700938 }
939
940 wpa_s->scan_id_count = 0;
941}
942
943
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -0700944static int wpa_set_ssids_from_scan_req(struct wpa_supplicant *wpa_s,
945 struct wpa_driver_scan_params *params,
946 size_t max_ssids)
947{
948 unsigned int i;
949
950 if (wpa_s->ssids_from_scan_req == NULL ||
951 wpa_s->num_ssids_from_scan_req == 0)
952 return 0;
953
954 if (wpa_s->num_ssids_from_scan_req > max_ssids) {
955 wpa_s->num_ssids_from_scan_req = max_ssids;
956 wpa_printf(MSG_DEBUG, "Over max scan SSIDs from scan req: %u",
957 (unsigned int) max_ssids);
958 }
959
960 for (i = 0; i < wpa_s->num_ssids_from_scan_req; i++) {
961 params->ssids[i].ssid = wpa_s->ssids_from_scan_req[i].ssid;
962 params->ssids[i].ssid_len =
963 wpa_s->ssids_from_scan_req[i].ssid_len;
964 wpa_hexdump_ascii(MSG_DEBUG, "specific SSID",
965 params->ssids[i].ssid,
966 params->ssids[i].ssid_len);
967 }
968
969 params->num_ssids = wpa_s->num_ssids_from_scan_req;
970 wpa_s->num_ssids_from_scan_req = 0;
971 return 1;
972}
973
974
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700975static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
976{
977 struct wpa_supplicant *wpa_s = eloop_ctx;
978 struct wpa_ssid *ssid;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800979 int ret, p2p_in_prog;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700980 struct wpabuf *extra_ie = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700981 struct wpa_driver_scan_params params;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700982 struct wpa_driver_scan_params *scan_params;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700983 size_t max_ssids;
Dmitry Shmidt203eadb2015-03-05 14:16:04 -0800984 int connect_without_scan = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700985
Dmitry Shmidt29333592017-01-09 12:27:11 -0800986 wpa_s->ignore_post_flush_scan_res = 0;
987
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700988 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
989 wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
990 return;
991 }
992
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800993 if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -0700994 wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
996 return;
997 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -0800998
Dmitry Shmidt5887a9d2012-09-14 10:47:43 -0700999 if (wpa_s->scanning) {
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001000 /*
1001 * If we are already in scanning state, we shall reschedule the
1002 * the incoming scan request.
1003 */
1004 wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
1005 wpa_supplicant_req_scan(wpa_s, 1, 0);
Dmitry Shmidt5887a9d2012-09-14 10:47:43 -07001006 return;
1007 }
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001008
Dmitry Shmidt04949592012-07-19 12:16:46 -07001009 if (!wpa_supplicant_enabled_networks(wpa_s) &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001010 wpa_s->scan_req == NORMAL_SCAN_REQ) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001011 wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
1012 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
1013 return;
1014 }
1015
1016 if (wpa_s->conf->ap_scan != 0 &&
1017 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
1018 wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
1019 "overriding ap_scan configuration");
1020 wpa_s->conf->ap_scan = 0;
1021 wpas_notify_ap_scan_changed(wpa_s);
1022 }
1023
1024 if (wpa_s->conf->ap_scan == 0) {
1025 wpa_supplicant_gen_assoc_event(wpa_s);
1026 return;
1027 }
1028
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001029 ssid = NULL;
1030 if (wpa_s->scan_req != MANUAL_SCAN_REQ &&
1031 wpa_s->connect_without_scan) {
1032 connect_without_scan = 1;
1033 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1034 if (ssid == wpa_s->connect_without_scan)
1035 break;
1036 }
1037 }
1038
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001039 p2p_in_prog = wpas_p2p_in_progress(wpa_s);
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001040 if (p2p_in_prog && p2p_in_prog != 2 &&
1041 (!ssid ||
1042 (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001043 wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
1044 wpa_supplicant_req_scan(wpa_s, 5, 0);
Dmitry Shmidt051af732013-10-22 13:52:46 -07001045 return;
1046 }
Dmitry Shmidt051af732013-10-22 13:52:46 -07001047
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001048 /*
1049 * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
1050 * used for changing modes inside wpa_supplicant (roaming,
1051 * auto-reconnect, etc). Discarding the scan might hurt these processes.
1052 * The normal use case for PNO is to suspend the host immediately after
1053 * starting PNO, so the periodic 100 ms attempts to run the scan do not
1054 * normally happen in practice multiple times, i.e., this is simply
1055 * restarting scanning once the host is woken up and PNO stopped.
1056 */
1057 if (wpa_s->pno || wpa_s->pno_sched_pending) {
1058 wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
1059 wpa_supplicant_req_scan(wpa_s, 0, 100000);
1060 return;
1061 }
1062
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001063 if (wpa_s->conf->ap_scan == 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064 max_ssids = 1;
1065 else {
1066 max_ssids = wpa_s->max_scan_ssids;
1067 if (max_ssids > WPAS_MAX_SCAN_SSIDS)
1068 max_ssids = WPAS_MAX_SCAN_SSIDS;
1069 }
1070
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001071 wpa_s->last_scan_req = wpa_s->scan_req;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001072 wpa_s->scan_req = NORMAL_SCAN_REQ;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001073
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001074 if (connect_without_scan) {
1075 wpa_s->connect_without_scan = NULL;
1076 if (ssid) {
1077 wpa_printf(MSG_DEBUG, "Start a pre-selected network "
1078 "without scan step");
1079 wpa_supplicant_associate(wpa_s, NULL, ssid);
1080 return;
1081 }
1082 }
1083
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001084 os_memset(&params, 0, sizeof(params));
1085
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001086 wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001087 if (wpa_s->wpa_state == WPA_DISCONNECTED ||
1088 wpa_s->wpa_state == WPA_INACTIVE)
1089 wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
1090
Dmitry Shmidt04949592012-07-19 12:16:46 -07001091 /*
1092 * If autoscan has set its own scanning parameters
1093 */
1094 if (wpa_s->autoscan_params != NULL) {
1095 scan_params = wpa_s->autoscan_params;
1096 goto scan;
1097 }
1098
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07001099 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
1100 wpa_set_ssids_from_scan_req(wpa_s, &params, max_ssids)) {
1101 wpa_printf(MSG_DEBUG, "Use specific SSIDs from SCAN command");
1102 goto ssid_list_set;
1103 }
1104
Dmitry Shmidt04949592012-07-19 12:16:46 -07001105#ifdef CONFIG_P2P
1106 if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001107 wpa_s->go_params && !wpa_s->conf->passive_scan) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001108 wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
1109 wpa_s->p2p_in_provisioning,
1110 wpa_s->show_group_started);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001111 params.ssids[0].ssid = wpa_s->go_params->ssid;
1112 params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
1113 params.num_ssids = 1;
1114 goto ssid_list_set;
1115 }
Dmitry Shmidt15907092014-03-25 10:42:57 -07001116
1117 if (wpa_s->p2p_in_invitation) {
1118 if (wpa_s->current_ssid) {
1119 wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation");
1120 params.ssids[0].ssid = wpa_s->current_ssid->ssid;
1121 params.ssids[0].ssid_len =
1122 wpa_s->current_ssid->ssid_len;
1123 params.num_ssids = 1;
1124 } else {
1125 wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation");
1126 }
1127 goto ssid_list_set;
1128 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07001129#endif /* CONFIG_P2P */
1130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001131 /* Find the starting point from which to continue scanning */
1132 ssid = wpa_s->conf->ssid;
1133 if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
1134 while (ssid) {
1135 if (ssid == wpa_s->prev_scan_ssid) {
1136 ssid = ssid->next;
1137 break;
1138 }
1139 ssid = ssid->next;
1140 }
1141 }
1142
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001143 if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001144#ifdef CONFIG_AP
1145 !wpa_s->ap_iface &&
1146#endif /* CONFIG_AP */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001147 wpa_s->conf->ap_scan == 2) {
Jouni Malinen75ecf522011-06-27 15:19:46 -07001148 wpa_s->connect_without_scan = NULL;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001149 wpa_s->prev_scan_wildcard = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001150 wpa_supplicant_assoc_try(wpa_s, ssid);
1151 return;
1152 } else if (wpa_s->conf->ap_scan == 2) {
1153 /*
1154 * User-initiated scan request in ap_scan == 2; scan with
1155 * wildcard SSID.
1156 */
1157 ssid = NULL;
Dmitry Shmidt98660862014-03-11 17:26:21 -07001158 } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) {
1159 /*
1160 * Perform single-channel single-SSID scan for
1161 * reassociate-to-same-BSS operation.
1162 */
1163 /* Setup SSID */
1164 ssid = wpa_s->current_ssid;
1165 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
1166 ssid->ssid, ssid->ssid_len);
1167 params.ssids[0].ssid = ssid->ssid;
1168 params.ssids[0].ssid_len = ssid->ssid_len;
1169 params.num_ssids = 1;
1170
1171 /*
1172 * Allocate memory for frequency array, allocate one extra
1173 * slot for the zero-terminator.
1174 */
1175 params.freqs = os_malloc(sizeof(int) * 2);
Dmitry Shmidtd5ab1b52016-06-21 12:38:41 -07001176 if (params.freqs) {
1177 params.freqs[0] = wpa_s->assoc_freq;
1178 params.freqs[1] = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07001179 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07001180
1181 /*
1182 * Reset the reattach flag so that we fall back to full scan if
1183 * this scan fails.
1184 */
1185 wpa_s->reattach = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001186 } else {
1187 struct wpa_ssid *start = ssid, *tssid;
1188 int freqs_set = 0;
1189 if (ssid == NULL && max_ssids > 1)
1190 ssid = wpa_s->conf->ssid;
1191 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001192 if (!wpas_network_disabled(wpa_s, ssid) &&
1193 ssid->scan_ssid) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001194 wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
1195 ssid->ssid, ssid->ssid_len);
1196 params.ssids[params.num_ssids].ssid =
1197 ssid->ssid;
1198 params.ssids[params.num_ssids].ssid_len =
1199 ssid->ssid_len;
1200 params.num_ssids++;
1201 if (params.num_ssids + 1 >= max_ssids)
1202 break;
1203 }
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001204
1205 if (!wpas_network_disabled(wpa_s, ssid)) {
1206 /*
1207 * Also add the SSID of the OWE BSS, to allow
1208 * discovery of transition mode APs more
1209 * quickly.
1210 */
1211 wpa_add_owe_scan_ssid(wpa_s, &params, ssid,
1212 max_ssids);
1213 }
1214
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001215 ssid = ssid->next;
1216 if (ssid == start)
1217 break;
1218 if (ssid == NULL && max_ssids > 1 &&
1219 start != wpa_s->conf->ssid)
1220 ssid = wpa_s->conf->ssid;
1221 }
1222
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001223 if (wpa_s->scan_id_count &&
1224 wpa_s->last_scan_req == MANUAL_SCAN_REQ)
1225 wpa_set_scan_ssids(wpa_s, &params, max_ssids);
1226
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001227 for (tssid = wpa_s->conf->ssid;
1228 wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid;
1229 tssid = tssid->next) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001230 if (wpas_network_disabled(wpa_s, tssid))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001231 continue;
Hai Shalomfdcde762020-04-02 11:19:20 -07001232 if (((params.freqs || !freqs_set) &&
1233 tssid->scan_freq) &&
1234 int_array_len(params.freqs) < 100) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001235 int_array_concat(&params.freqs,
1236 tssid->scan_freq);
1237 } else {
1238 os_free(params.freqs);
1239 params.freqs = NULL;
1240 }
1241 freqs_set = 1;
1242 }
1243 int_array_sort_unique(params.freqs);
1244 }
1245
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001246 if (ssid && max_ssids == 1) {
1247 /*
1248 * If the driver is limited to 1 SSID at a time interleave
1249 * wildcard SSID scans with specific SSID scans to avoid
1250 * waiting a long time for a wildcard scan.
1251 */
1252 if (!wpa_s->prev_scan_wildcard) {
1253 params.ssids[0].ssid = NULL;
1254 params.ssids[0].ssid_len = 0;
1255 wpa_s->prev_scan_wildcard = 1;
1256 wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
1257 "wildcard SSID (Interleave with specific)");
1258 } else {
1259 wpa_s->prev_scan_ssid = ssid;
1260 wpa_s->prev_scan_wildcard = 0;
1261 wpa_dbg(wpa_s, MSG_DEBUG,
1262 "Starting AP scan for specific SSID: %s",
1263 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264 }
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001265 } else if (ssid) {
1266 /* max_ssids > 1 */
1267
1268 wpa_s->prev_scan_ssid = ssid;
1269 wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
1270 "the scan request");
1271 params.num_ssids++;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001272 } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
1273 wpa_s->manual_scan_passive && params.num_ssids == 0) {
1274 wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001275 } else if (wpa_s->conf->passive_scan) {
1276 wpa_dbg(wpa_s, MSG_DEBUG,
1277 "Use passive scan based on configuration");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001278 } else {
1279 wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
1280 params.num_ssids++;
1281 wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
1282 "SSID");
1283 }
1284
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07001285ssid_list_set:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001286 wpa_supplicant_optimize_freqs(wpa_s, &params);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001287 extra_ie = wpa_supplicant_extra_ies(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001288
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001289 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001290 wpa_s->manual_scan_only_new) {
1291 wpa_printf(MSG_DEBUG,
1292 "Request driver to clear scan cache due to manual only_new=1 scan");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001293 params.only_new_results = 1;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001294 }
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001295
1296 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
1297 wpa_s->manual_scan_freqs) {
1298 wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
1299 params.freqs = wpa_s->manual_scan_freqs;
1300 wpa_s->manual_scan_freqs = NULL;
1301 }
1302
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001303 if (params.freqs == NULL && wpa_s->select_network_scan_freqs) {
1304 wpa_dbg(wpa_s, MSG_DEBUG,
1305 "Limit select_network scan to specified channels");
1306 params.freqs = wpa_s->select_network_scan_freqs;
1307 wpa_s->select_network_scan_freqs = NULL;
1308 }
1309
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001310 if (params.freqs == NULL && wpa_s->next_scan_freqs) {
1311 wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
1312 "generated frequency list");
1313 params.freqs = wpa_s->next_scan_freqs;
1314 } else
1315 os_free(wpa_s->next_scan_freqs);
1316 wpa_s->next_scan_freqs = NULL;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001317 wpa_setband_scan_freqs(wpa_s, &params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001318
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07001319 /* See if user specified frequencies. If so, scan only those. */
Hai Shalom60840252021-02-19 19:02:11 -08001320 if (wpa_s->last_scan_req == INITIAL_SCAN_REQ &&
1321 wpa_s->conf->initial_freq_list && !params.freqs) {
1322 wpa_dbg(wpa_s, MSG_DEBUG,
1323 "Optimize scan based on conf->initial_freq_list");
1324 int_array_concat(&params.freqs, wpa_s->conf->initial_freq_list);
1325 } else if (wpa_s->conf->freq_list && !params.freqs) {
Dmitry Shmidt51b6ea82013-05-08 10:42:09 -07001326 wpa_dbg(wpa_s, MSG_DEBUG,
1327 "Optimize scan based on conf->freq_list");
1328 int_array_concat(&params.freqs, wpa_s->conf->freq_list);
1329 }
1330
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001331 /* Use current associated channel? */
1332 if (wpa_s->conf->scan_cur_freq && !params.freqs) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001333 unsigned int num = wpa_s->num_multichan_concurrent;
1334
1335 params.freqs = os_calloc(num + 1, sizeof(int));
1336 if (params.freqs) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001337 num = get_shared_radio_freqs(wpa_s, params.freqs, num,
1338 false);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001339 if (num > 0) {
1340 wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
1341 "current operating channels since "
1342 "scan_cur_freq is enabled");
1343 } else {
1344 os_free(params.freqs);
1345 params.freqs = NULL;
1346 }
Dmitry Shmidtea69e842013-05-13 14:52:28 -07001347 }
1348 }
1349
Hai Shalomce48b4a2018-09-05 11:41:35 -07001350#ifdef CONFIG_MBO
1351 if (wpa_s->enable_oce & OCE_STA)
1352 params.oce_scan = 1;
1353#endif /* CONFIG_MBO */
1354
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001355 params.filter_ssids = wpa_supplicant_build_filter_ssids(
1356 wpa_s->conf, &params.num_filter_ssids);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001357 if (extra_ie) {
1358 params.extra_ies = wpabuf_head(extra_ie);
1359 params.extra_ies_len = wpabuf_len(extra_ie);
1360 }
1361
1362#ifdef CONFIG_P2P
Dmitry Shmidt413dde72014-04-11 10:23:22 -07001363 if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation ||
Dmitry Shmidt04949592012-07-19 12:16:46 -07001364 (wpa_s->show_group_started && wpa_s->go_params)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001365 /*
1366 * The interface may not yet be in P2P mode, so we have to
1367 * explicitly request P2P probe to disable CCK rates.
1368 */
1369 params.p2p_probe = 1;
1370 }
1371#endif /* CONFIG_P2P */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001372
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001373 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001374 wpa_s->wpa_state <= WPA_SCANNING)
1375 wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_scan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001376
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001377 if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
1378 struct wpa_bss *bss;
1379
1380 params.bssid = wpa_s->next_scan_bssid;
1381 bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
Hai Shalomfdcde762020-04-02 11:19:20 -07001382 if (!wpa_s->next_scan_bssid_wildcard_ssid &&
1383 bss && bss->ssid_len && params.num_ssids == 1 &&
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001384 params.ssids[0].ssid_len == 0) {
1385 params.ssids[0].ssid = bss->ssid;
1386 params.ssids[0].ssid_len = bss->ssid_len;
1387 wpa_dbg(wpa_s, MSG_DEBUG,
1388 "Scan a previously specified BSSID " MACSTR
1389 " and SSID %s",
1390 MAC2STR(params.bssid),
1391 wpa_ssid_txt(bss->ssid, bss->ssid_len));
1392 } else {
1393 wpa_dbg(wpa_s, MSG_DEBUG,
1394 "Scan a previously specified BSSID " MACSTR,
1395 MAC2STR(params.bssid));
1396 }
1397 }
1398
Sunil8cd6f4d2022-06-28 18:40:46 +00001399 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
1400 wpa_s->manual_non_coloc_6ghz) {
1401 wpa_dbg(wpa_s, MSG_DEBUG, "Collocated 6 GHz logic is disabled");
1402 params.non_coloc_6ghz = 1;
1403 }
1404
Dmitry Shmidt04949592012-07-19 12:16:46 -07001405 scan_params = &params;
1406
1407scan:
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001408#ifdef CONFIG_P2P
1409 /*
1410 * If the driver does not support multi-channel concurrency and a
1411 * virtual interface that shares the same radio with the wpa_s interface
1412 * is operating there may not be need to scan other channels apart from
1413 * the current operating channel on the other virtual interface. Filter
1414 * out other channels in case we are trying to find a connection for a
1415 * station interface when we are not configured to prefer station
1416 * connection and a concurrent operation is already in process.
1417 */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001418 if (wpa_s->scan_for_connection &&
1419 wpa_s->last_scan_req == NORMAL_SCAN_REQ &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001420 !scan_params->freqs && !params.freqs &&
1421 wpas_is_p2p_prioritized(wpa_s) &&
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001422 wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
1423 non_p2p_network_enabled(wpa_s)) {
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001424 unsigned int num = wpa_s->num_multichan_concurrent;
1425
1426 params.freqs = os_calloc(num + 1, sizeof(int));
1427 if (params.freqs) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001428 /*
1429 * Exclude the operating frequency of the current
1430 * interface since we're looking to transition off of
1431 * it.
1432 */
1433 num = get_shared_radio_freqs(wpa_s, params.freqs, num,
1434 true);
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001435 if (num > 0 && num == wpa_s->num_multichan_concurrent) {
1436 wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
1437 } else {
1438 os_free(params.freqs);
1439 params.freqs = NULL;
1440 }
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001441 }
1442 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001443
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001444 if (!params.freqs && is_6ghz_supported(wpa_s) &&
1445 (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning))
1446 wpas_p2p_scan_freqs(wpa_s, &params, true);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001447#endif /* CONFIG_P2P */
1448
Dmitry Shmidt04949592012-07-19 12:16:46 -07001449 ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001450
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001451 if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
1452 !wpa_s->manual_scan_freqs) {
1453 /* Restore manual_scan_freqs for the next attempt */
1454 wpa_s->manual_scan_freqs = params.freqs;
1455 params.freqs = NULL;
1456 }
1457
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001458 wpabuf_free(extra_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001459 os_free(params.freqs);
1460 os_free(params.filter_ssids);
Hai Shalomc3565922019-10-28 11:58:20 -07001461 os_free(params.mac_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001462
1463 if (ret) {
1464 wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001465 if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
1466 wpa_supplicant_set_state(wpa_s,
1467 wpa_s->scan_prev_wpa_state);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001468 /* Restore scan_req since we will try to scan again */
Dmitry Shmidt01904cf2013-12-05 11:08:35 -08001469 wpa_s->scan_req = wpa_s->last_scan_req;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001470 wpa_supplicant_req_scan(wpa_s, 1, 0);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001471 } else {
1472 wpa_s->scan_for_connection = 0;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001473#ifdef CONFIG_INTERWORKING
1474 wpa_s->interworking_fast_assoc_tried = 0;
1475#endif /* CONFIG_INTERWORKING */
Hai Shalomfdcde762020-04-02 11:19:20 -07001476 wpa_s->next_scan_bssid_wildcard_ssid = 0;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08001477 if (params.bssid)
1478 os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001479 }
1480}
1481
1482
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001483void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
1484{
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001485 struct os_reltime remaining, new_int;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001486 int cancelled;
1487
1488 cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
1489 &remaining);
1490
1491 new_int.sec = sec;
1492 new_int.usec = 0;
Dmitry Shmidtfa3fc4a2013-11-21 13:34:38 -08001493 if (cancelled && os_reltime_before(&remaining, &new_int)) {
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001494 new_int.sec = remaining.sec;
1495 new_int.usec = remaining.usec;
1496 }
1497
Dmitry Shmidt051af732013-10-22 13:52:46 -07001498 if (cancelled) {
1499 eloop_register_timeout(new_int.sec, new_int.usec,
1500 wpa_supplicant_scan, wpa_s, NULL);
1501 }
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08001502 wpa_s->scan_interval = sec;
1503}
1504
1505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001506/**
1507 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
1508 * @wpa_s: Pointer to wpa_supplicant data
1509 * @sec: Number of seconds after which to scan
1510 * @usec: Number of microseconds after which to scan
1511 *
1512 * This function is used to schedule a scan for neighboring access points after
1513 * the specified time.
1514 */
1515void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
1516{
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001517 int res;
1518
1519 if (wpa_s->p2p_mgmt) {
1520 wpa_dbg(wpa_s, MSG_DEBUG,
1521 "Ignore scan request (%d.%06d sec) on p2p_mgmt interface",
1522 sec, usec);
1523 return;
1524 }
1525
1526 res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
1527 NULL);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001528 if (res == 1) {
1529 wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08001530 sec, usec);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001531 } else if (res == 0) {
1532 wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner",
1533 sec, usec);
1534 } else {
1535 wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec",
1536 sec, usec);
1537 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001538 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001539}
1540
1541
1542/**
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001543 * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan
1544 * @wpa_s: Pointer to wpa_supplicant data
1545 * @sec: Number of seconds after which to scan
1546 * @usec: Number of microseconds after which to scan
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001547 * Returns: 0 on success or -1 otherwise
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001548 *
1549 * This function is used to schedule periodic scans for neighboring
1550 * access points after the specified time.
1551 */
1552int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
1553 int sec, int usec)
1554{
1555 if (!wpa_s->sched_scan_supported)
1556 return -1;
1557
1558 eloop_register_timeout(sec, usec,
1559 wpa_supplicant_delayed_sched_scan_timeout,
1560 wpa_s, NULL);
1561
1562 return 0;
1563}
1564
1565
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001566static void
1567wpa_scan_set_relative_rssi_params(struct wpa_supplicant *wpa_s,
1568 struct wpa_driver_scan_params *params)
1569{
1570 if (wpa_s->wpa_state != WPA_COMPLETED ||
1571 !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI) ||
1572 wpa_s->srp.relative_rssi_set == 0)
1573 return;
1574
1575 params->relative_rssi_set = 1;
1576 params->relative_rssi = wpa_s->srp.relative_rssi;
1577
1578 if (wpa_s->srp.relative_adjust_rssi == 0)
1579 return;
1580
1581 params->relative_adjust_band = wpa_s->srp.relative_adjust_band;
1582 params->relative_adjust_rssi = wpa_s->srp.relative_adjust_rssi;
1583}
1584
1585
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001586/**
1587 * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
1588 * @wpa_s: Pointer to wpa_supplicant data
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001589 * Returns: 0 is sched_scan was started or -1 otherwise
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001590 *
1591 * This function is used to schedule periodic scans for neighboring
1592 * access points repeating the scan continuously.
1593 */
1594int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
1595{
1596 struct wpa_driver_scan_params params;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001597 struct wpa_driver_scan_params *scan_params;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001598 enum wpa_states prev_state;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001599 struct wpa_ssid *ssid = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001600 struct wpabuf *extra_ie = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001601 int ret;
1602 unsigned int max_sched_scan_ssids;
1603 int wildcard = 0;
1604 int need_ssids;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001605 struct sched_scan_plan scan_plan;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001606
1607 if (!wpa_s->sched_scan_supported)
1608 return -1;
1609
1610 if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
1611 max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
1612 else
1613 max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001614 if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001615 return -1;
1616
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001617 wpa_s->sched_scan_stop_req = 0;
1618
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001619 if (wpa_s->sched_scanning) {
1620 wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
1621 return 0;
1622 }
1623
1624 need_ssids = 0;
1625 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001626 if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001627 /* Use wildcard SSID to find this network */
1628 wildcard = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001629 } else if (!wpas_network_disabled(wpa_s, ssid) &&
1630 ssid->ssid_len)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001631 need_ssids++;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001632
1633#ifdef CONFIG_WPS
1634 if (!wpas_network_disabled(wpa_s, ssid) &&
1635 ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
1636 /*
1637 * Normal scan is more reliable and faster for WPS
1638 * operations and since these are for short periods of
1639 * time, the benefit of trying to use sched_scan would
1640 * be limited.
1641 */
1642 wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
1643 "sched_scan for WPS");
1644 return -1;
1645 }
1646#endif /* CONFIG_WPS */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001647 }
1648 if (wildcard)
1649 need_ssids++;
1650
1651 if (wpa_s->normal_scans < 3 &&
1652 (need_ssids <= wpa_s->max_scan_ssids ||
1653 wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
1654 /*
1655 * When normal scan can speed up operations, use that for the
1656 * first operations before starting the sched_scan to allow
1657 * user space sleep more. We do this only if the normal scan
1658 * has functionality that is suitable for this or if the
1659 * sched_scan does not have better support for multiple SSIDs.
1660 */
1661 wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
1662 "sched_scan for initial scans (normal_scans=%d)",
1663 wpa_s->normal_scans);
1664 return -1;
1665 }
1666
1667 os_memset(&params, 0, sizeof(params));
1668
1669 /* If we can't allocate space for the filters, we just don't filter */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001670 params.filter_ssids = os_calloc(wpa_s->max_match_sets,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001671 sizeof(struct wpa_driver_scan_filter));
1672
1673 prev_state = wpa_s->wpa_state;
1674 if (wpa_s->wpa_state == WPA_DISCONNECTED ||
1675 wpa_s->wpa_state == WPA_INACTIVE)
1676 wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
1677
Dmitry Shmidt04949592012-07-19 12:16:46 -07001678 if (wpa_s->autoscan_params != NULL) {
1679 scan_params = wpa_s->autoscan_params;
1680 goto scan;
1681 }
1682
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001683 /* Find the starting point from which to continue scanning */
1684 ssid = wpa_s->conf->ssid;
1685 if (wpa_s->prev_sched_ssid) {
1686 while (ssid) {
1687 if (ssid == wpa_s->prev_sched_ssid) {
1688 ssid = ssid->next;
1689 break;
1690 }
1691 ssid = ssid->next;
1692 }
1693 }
1694
1695 if (!ssid || !wpa_s->prev_sched_ssid) {
1696 wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001697 wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
1698 wpa_s->first_sched_scan = 1;
1699 ssid = wpa_s->conf->ssid;
1700 wpa_s->prev_sched_ssid = ssid;
1701 }
1702
1703 if (wildcard) {
1704 wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
1705 params.num_ssids++;
1706 }
1707
1708 while (ssid) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001709 if (wpas_network_disabled(wpa_s, ssid))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001710 goto next;
1711
1712 if (params.num_filter_ssids < wpa_s->max_match_sets &&
1713 params.filter_ssids && ssid->ssid && ssid->ssid_len) {
1714 wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
1715 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1716 os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
1717 ssid->ssid, ssid->ssid_len);
1718 params.filter_ssids[params.num_filter_ssids].ssid_len =
1719 ssid->ssid_len;
1720 params.num_filter_ssids++;
1721 } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
1722 {
1723 wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
1724 "filter for sched_scan - drop filter");
1725 os_free(params.filter_ssids);
1726 params.filter_ssids = NULL;
1727 params.num_filter_ssids = 0;
1728 }
1729
1730 if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
1731 if (params.num_ssids == max_sched_scan_ssids)
1732 break; /* only room for broadcast SSID */
1733 wpa_dbg(wpa_s, MSG_DEBUG,
1734 "add to active scan ssid: %s",
1735 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1736 params.ssids[params.num_ssids].ssid =
1737 ssid->ssid;
1738 params.ssids[params.num_ssids].ssid_len =
1739 ssid->ssid_len;
1740 params.num_ssids++;
1741 if (params.num_ssids >= max_sched_scan_ssids) {
1742 wpa_s->prev_sched_ssid = ssid;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001743 do {
1744 ssid = ssid->next;
1745 } while (ssid &&
1746 (wpas_network_disabled(wpa_s, ssid) ||
1747 !ssid->scan_ssid));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001748 break;
1749 }
1750 }
1751
1752 next:
1753 wpa_s->prev_sched_ssid = ssid;
1754 ssid = ssid->next;
1755 }
1756
1757 if (params.num_filter_ssids == 0) {
1758 os_free(params.filter_ssids);
1759 params.filter_ssids = NULL;
1760 }
1761
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001762 extra_ie = wpa_supplicant_extra_ies(wpa_s);
1763 if (extra_ie) {
1764 params.extra_ies = wpabuf_head(extra_ie);
1765 params.extra_ies_len = wpabuf_len(extra_ie);
1766 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001767
Dmitry Shmidt18463232014-01-24 12:29:41 -08001768 if (wpa_s->conf->filter_rssi)
1769 params.filter_rssi = wpa_s->conf->filter_rssi;
1770
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001771 /* See if user specified frequencies. If so, scan only those. */
1772 if (wpa_s->conf->freq_list && !params.freqs) {
1773 wpa_dbg(wpa_s, MSG_DEBUG,
1774 "Optimize scan based on conf->freq_list");
1775 int_array_concat(&params.freqs, wpa_s->conf->freq_list);
1776 }
1777
Hai Shalomce48b4a2018-09-05 11:41:35 -07001778#ifdef CONFIG_MBO
1779 if (wpa_s->enable_oce & OCE_STA)
1780 params.oce_scan = 1;
1781#endif /* CONFIG_MBO */
1782
Dmitry Shmidt04949592012-07-19 12:16:46 -07001783 scan_params = &params;
1784
1785scan:
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001786 wpa_s->sched_scan_timed_out = 0;
1787
1788 /*
1789 * We cannot support multiple scan plans if the scan request includes
1790 * too many SSID's, so in this case use only the last scan plan and make
1791 * it run infinitely. It will be stopped by the timeout.
1792 */
1793 if (wpa_s->sched_scan_plans_num == 1 ||
1794 (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) {
1795 params.sched_scan_plans = wpa_s->sched_scan_plans;
1796 params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
1797 } else if (wpa_s->sched_scan_plans_num > 1) {
1798 wpa_dbg(wpa_s, MSG_DEBUG,
1799 "Too many SSIDs. Default to using single scheduled_scan plan");
1800 params.sched_scan_plans =
1801 &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num -
1802 1];
1803 params.sched_scan_plans_num = 1;
1804 } else {
1805 if (wpa_s->conf->sched_scan_interval)
1806 scan_plan.interval = wpa_s->conf->sched_scan_interval;
1807 else
1808 scan_plan.interval = 10;
1809
1810 if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) {
1811 wpa_printf(MSG_WARNING,
1812 "Scan interval too long(%u), use the maximum allowed(%u)",
1813 scan_plan.interval,
1814 wpa_s->max_sched_scan_plan_interval);
1815 scan_plan.interval =
1816 wpa_s->max_sched_scan_plan_interval;
1817 }
1818
1819 scan_plan.iterations = 0;
1820 params.sched_scan_plans = &scan_plan;
1821 params.sched_scan_plans_num = 1;
1822 }
1823
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001824 params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay;
1825
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001826 if (ssid || !wpa_s->first_sched_scan) {
1827 wpa_dbg(wpa_s, MSG_DEBUG,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001828 "Starting sched scan after %u seconds: interval %u timeout %d",
1829 params.sched_scan_start_delay,
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001830 params.sched_scan_plans[0].interval,
1831 wpa_s->sched_scan_timeout);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001832 } else {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001833 wpa_dbg(wpa_s, MSG_DEBUG,
1834 "Starting sched scan after %u seconds (no timeout)",
1835 params.sched_scan_start_delay);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001836 }
1837
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001838 wpa_setband_scan_freqs(wpa_s, scan_params);
1839
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001840 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
Hai Shalomc3565922019-10-28 11:58:20 -07001841 wpa_s->wpa_state <= WPA_SCANNING)
1842 wpa_setup_mac_addr_rand_params(&params,
1843 wpa_s->mac_addr_sched_scan);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001844
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001845 wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
1846
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001847 ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001848 wpabuf_free(extra_ie);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001849 os_free(params.filter_ssids);
Hai Shalomc3565922019-10-28 11:58:20 -07001850 os_free(params.mac_addr);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001851 if (ret) {
1852 wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
1853 if (prev_state != wpa_s->wpa_state)
1854 wpa_supplicant_set_state(wpa_s, prev_state);
1855 return ret;
1856 }
1857
1858 /* If we have more SSIDs to scan, add a timeout so we scan them too */
1859 if (ssid || !wpa_s->first_sched_scan) {
1860 wpa_s->sched_scan_timed_out = 0;
1861 eloop_register_timeout(wpa_s->sched_scan_timeout, 0,
1862 wpa_supplicant_sched_scan_timeout,
1863 wpa_s, NULL);
1864 wpa_s->first_sched_scan = 0;
1865 wpa_s->sched_scan_timeout /= 2;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001866 params.sched_scan_plans[0].interval *= 2;
1867 if ((unsigned int) wpa_s->sched_scan_timeout <
1868 params.sched_scan_plans[0].interval ||
1869 params.sched_scan_plans[0].interval >
1870 wpa_s->max_sched_scan_plan_interval) {
1871 params.sched_scan_plans[0].interval = 10;
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001872 wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
1873 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001874 }
1875
Dmitry Shmidt2f023192013-03-12 12:44:17 -07001876 /* If there is no more ssids, start next time from the beginning */
1877 if (!ssid)
1878 wpa_s->prev_sched_ssid = NULL;
1879
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001880 return 0;
1881}
1882
1883
1884/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001885 * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
1886 * @wpa_s: Pointer to wpa_supplicant data
1887 *
1888 * This function is used to cancel a scan request scheduled with
1889 * wpa_supplicant_req_scan().
1890 */
1891void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
1892{
1893 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
1894 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001895}
1896
1897
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001898/**
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -07001899 * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan
1900 * @wpa_s: Pointer to wpa_supplicant data
1901 *
1902 * This function is used to stop a delayed scheduled scan.
1903 */
1904void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)
1905{
1906 if (!wpa_s->sched_scan_supported)
1907 return;
1908
1909 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan");
1910 eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout,
1911 wpa_s, NULL);
1912}
1913
1914
1915/**
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001916 * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
1917 * @wpa_s: Pointer to wpa_supplicant data
1918 *
1919 * This function is used to stop a periodic scheduled scan.
1920 */
1921void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
1922{
1923 if (!wpa_s->sched_scanning)
1924 return;
1925
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001926 if (wpa_s->sched_scanning)
1927 wpa_s->sched_scan_stop_req = 1;
1928
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001929 wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
1930 eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
1931 wpa_supplicant_stop_sched_scan(wpa_s);
1932}
1933
1934
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001935/**
1936 * wpa_supplicant_notify_scanning - Indicate possible scan state change
1937 * @wpa_s: Pointer to wpa_supplicant data
1938 * @scanning: Whether scanning is currently in progress
1939 *
1940 * This function is to generate scanning notifycations. It is called whenever
1941 * there may have been a change in scanning (scan started, completed, stopped).
1942 * wpas_notify_scanning() is called whenever the scanning state changed from the
1943 * previously notified state.
1944 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001945void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
1946 int scanning)
1947{
1948 if (wpa_s->scanning != scanning) {
1949 wpa_s->scanning = scanning;
1950 wpas_notify_scanning(wpa_s);
1951 }
1952}
1953
1954
1955static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
1956{
1957 int rate = 0;
1958 const u8 *ie;
1959 int i;
1960
1961 ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
1962 for (i = 0; ie && i < ie[1]; i++) {
1963 if ((ie[i + 2] & 0x7f) > rate)
1964 rate = ie[i + 2] & 0x7f;
1965 }
1966
1967 ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
1968 for (i = 0; ie && i < ie[1]; i++) {
1969 if ((ie[i + 2] & 0x7f) > rate)
1970 rate = ie[i + 2] & 0x7f;
1971 }
1972
1973 return rate;
1974}
1975
1976
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001977/**
1978 * wpa_scan_get_ie - Fetch a specified information element from a scan result
1979 * @res: Scan result entry
1980 * @ie: Information element identitifier (WLAN_EID_*)
1981 * Returns: Pointer to the information element (id field) or %NULL if not found
1982 *
1983 * This function returns the first matching information element in the scan
1984 * result.
1985 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001986const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
1987{
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001988 size_t ie_len = res->ie_len;
1989
1990 /* Use the Beacon frame IEs if res->ie_len is not available */
1991 if (!ie_len)
1992 ie_len = res->beacon_ie_len;
1993
1994 return get_ie((const u8 *) (res + 1), ie_len, ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001995}
1996
1997
Sunil Ravi89eba102022-09-13 21:04:37 -07001998const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type)
1999{
2000 size_t ie_len = res->ie_len;
2001
2002 /* Use the Beacon frame IEs if res->ie_len is not available */
2003 if (!ie_len)
2004 ie_len = res->beacon_ie_len;
2005
2006 return get_ml_ie((const u8 *) (res + 1), ie_len, type);
2007}
2008
2009
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002010/**
2011 * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
2012 * @res: Scan result entry
2013 * @vendor_type: Vendor type (four octets starting the IE payload)
2014 * Returns: Pointer to the information element (id field) or %NULL if not found
2015 *
2016 * This function returns the first matching information element in the scan
2017 * result.
2018 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002019const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
2020 u32 vendor_type)
2021{
Hai Shalom60840252021-02-19 19:02:11 -08002022 const u8 *ies;
2023 const struct element *elem;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002024
Hai Shalom60840252021-02-19 19:02:11 -08002025 ies = (const u8 *) (res + 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002026
Hai Shalom60840252021-02-19 19:02:11 -08002027 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, res->ie_len) {
2028 if (elem->datalen >= 4 &&
2029 vendor_type == WPA_GET_BE32(elem->data))
2030 return &elem->id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002031 }
2032
2033 return NULL;
2034}
2035
2036
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002037/**
Dmitry Shmidt96571392013-10-14 12:54:46 -07002038 * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
2039 * @res: Scan result entry
2040 * @vendor_type: Vendor type (four octets starting the IE payload)
2041 * Returns: Pointer to the information element (id field) or %NULL if not found
2042 *
2043 * This function returns the first matching information element in the scan
2044 * result.
2045 *
2046 * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
2047 * from Beacon frames instead of either Beacon or Probe Response frames.
2048 */
2049const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
2050 u32 vendor_type)
2051{
Hai Shalom60840252021-02-19 19:02:11 -08002052 const u8 *ies;
2053 const struct element *elem;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002054
2055 if (res->beacon_ie_len == 0)
2056 return NULL;
2057
Hai Shalom60840252021-02-19 19:02:11 -08002058 ies = (const u8 *) (res + 1);
2059 ies += res->ie_len;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002060
Hai Shalom60840252021-02-19 19:02:11 -08002061 for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
2062 res->beacon_ie_len) {
2063 if (elem->datalen >= 4 &&
2064 vendor_type == WPA_GET_BE32(elem->data))
2065 return &elem->id;
Dmitry Shmidt96571392013-10-14 12:54:46 -07002066 }
2067
2068 return NULL;
2069}
2070
2071
2072/**
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002073 * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
2074 * @res: Scan result entry
2075 * @vendor_type: Vendor type (four octets starting the IE payload)
2076 * Returns: Pointer to the information element payload or %NULL if not found
2077 *
2078 * This function returns concatenated payload of possibly fragmented vendor
2079 * specific information elements in the scan result. The caller is responsible
2080 * for freeing the returned buffer.
2081 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002082struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
2083 u32 vendor_type)
2084{
2085 struct wpabuf *buf;
2086 const u8 *end, *pos;
2087
2088 buf = wpabuf_alloc(res->ie_len);
2089 if (buf == NULL)
2090 return NULL;
2091
2092 pos = (const u8 *) (res + 1);
2093 end = pos + res->ie_len;
2094
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002095 while (end - pos > 1) {
Hai Shalom60840252021-02-19 19:02:11 -08002096 u8 ie, len;
2097
2098 ie = pos[0];
2099 len = pos[1];
2100 if (len > end - pos - 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002101 break;
Hai Shalom60840252021-02-19 19:02:11 -08002102 pos += 2;
2103 if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
2104 vendor_type == WPA_GET_BE32(pos))
2105 wpabuf_put_data(buf, pos + 4, len - 4);
2106 pos += len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002107 }
2108
2109 if (wpabuf_len(buf) == 0) {
2110 wpabuf_free(buf);
2111 buf = NULL;
2112 }
2113
2114 return buf;
2115}
2116
2117
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002118/* Compare function for sorting scan results. Return >0 if @b is considered
2119 * better. */
2120static int wpa_scan_result_compar(const void *a, const void *b)
2121{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002122#define MIN(a,b) a < b ? a : b
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002123 struct wpa_scan_res **_wa = (void *) a;
2124 struct wpa_scan_res **_wb = (void *) b;
2125 struct wpa_scan_res *wa = *_wa;
2126 struct wpa_scan_res *wb = *_wb;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002127 int wpa_a, wpa_b;
2128 int snr_a, snr_b, snr_a_full, snr_b_full;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002129
2130 /* WPA/WPA2 support preferred */
2131 wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
2132 wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
2133 wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
2134 wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
2135
2136 if (wpa_b && !wpa_a)
2137 return 1;
2138 if (!wpa_b && wpa_a)
2139 return -1;
2140
2141 /* privacy support preferred */
2142 if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
2143 (wb->caps & IEEE80211_CAP_PRIVACY))
2144 return 1;
2145 if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
2146 (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
2147 return -1;
2148
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002149 if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002150 snr_a_full = wa->snr;
2151 snr_a = MIN(wa->snr, GREAT_SNR);
2152 snr_b_full = wb->snr;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002153 snr_b = MIN(wb->snr, GREAT_SNR);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002154 } else {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002155 /* Level is not in dBm, so we can't calculate
2156 * SNR. Just use raw level (units unknown). */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002157 snr_a = snr_a_full = wa->level;
2158 snr_b = snr_b_full = wb->level;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002159 }
2160
Hai Shaloma20dcd72022-02-04 13:43:00 -08002161 /* If SNR is close, decide by max rate or frequency band. For cases
2162 * involving the 6 GHz band, use the throughput estimate irrespective
2163 * of the SNR difference since the LPI/VLP rules may result in
2164 * significant differences in SNR for cases where the estimated
2165 * throughput can be considerably higher with the lower SNR. */
2166 if (snr_a && snr_b && (abs(snr_b - snr_a) < 7 ||
2167 is_6ghz_freq(wa->freq) ||
2168 is_6ghz_freq(wb->freq))) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002169 if (wa->est_throughput != wb->est_throughput)
Hai Shalom021b0b52019-04-10 11:17:58 -07002170 return (int) wb->est_throughput -
2171 (int) wa->est_throughput;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002172 }
2173 if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
2174 (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002175 if (is_6ghz_freq(wa->freq) ^ is_6ghz_freq(wb->freq))
2176 return is_6ghz_freq(wa->freq) ? -1 : 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002177 if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
2178 return IS_5GHZ(wa->freq) ? -1 : 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002179 }
2180
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002181 /* all things being equal, use SNR; if SNRs are
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002182 * identical, use quality values since some drivers may only report
2183 * that value and leave the signal level zero */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002184 if (snr_b_full == snr_a_full)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002185 return wb->qual - wa->qual;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002186 return snr_b_full - snr_a_full;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002187#undef MIN
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002188}
2189
2190
2191#ifdef CONFIG_WPS
2192/* Compare function for sorting scan results when searching a WPS AP for
2193 * provisioning. Return >0 if @b is considered better. */
2194static int wpa_scan_result_wps_compar(const void *a, const void *b)
2195{
2196 struct wpa_scan_res **_wa = (void *) a;
2197 struct wpa_scan_res **_wb = (void *) b;
2198 struct wpa_scan_res *wa = *_wa;
2199 struct wpa_scan_res *wb = *_wb;
2200 int uses_wps_a, uses_wps_b;
2201 struct wpabuf *wps_a, *wps_b;
2202 int res;
2203
2204 /* Optimization - check WPS IE existence before allocated memory and
2205 * doing full reassembly. */
2206 uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
2207 uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
2208 if (uses_wps_a && !uses_wps_b)
2209 return -1;
2210 if (!uses_wps_a && uses_wps_b)
2211 return 1;
2212
2213 if (uses_wps_a && uses_wps_b) {
2214 wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
2215 wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
2216 res = wps_ap_priority_compar(wps_a, wps_b);
2217 wpabuf_free(wps_a);
2218 wpabuf_free(wps_b);
2219 if (res)
2220 return res;
2221 }
2222
2223 /*
2224 * Do not use current AP security policy as a sorting criteria during
2225 * WPS provisioning step since the AP may get reconfigured at the
2226 * completion of provisioning.
2227 */
2228
2229 /* all things being equal, use signal level; if signal levels are
2230 * identical, use quality values since some drivers may only report
2231 * that value and leave the signal level zero */
2232 if (wb->level == wa->level)
2233 return wb->qual - wa->qual;
2234 return wb->level - wa->level;
2235}
2236#endif /* CONFIG_WPS */
2237
2238
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002239static void dump_scan_res(struct wpa_scan_results *scan_res)
2240{
2241#ifndef CONFIG_NO_STDOUT_DEBUG
2242 size_t i;
2243
2244 if (scan_res->res == NULL || scan_res->num == 0)
2245 return;
2246
2247 wpa_printf(MSG_EXCESSIVE, "Sorted scan results");
2248
2249 for (i = 0; i < scan_res->num; i++) {
2250 struct wpa_scan_res *r = scan_res->res[i];
Dmitry Shmidt04949592012-07-19 12:16:46 -07002251 u8 *pos;
Sunil Ravia04bd252022-05-02 22:54:18 -07002252 const u8 *ssid_ie, *ssid = NULL;
2253 size_t ssid_len = 0;
2254
2255 ssid_ie = wpa_scan_get_ie(r, WLAN_EID_SSID);
2256 if (ssid_ie) {
2257 ssid = ssid_ie + 2;
2258 ssid_len = ssid_ie[1];
2259 }
2260
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002261 if (r->flags & WPA_SCAN_LEVEL_DBM) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002262 int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
2263
Sunil Ravia04bd252022-05-02 22:54:18 -07002264 wpa_printf(MSG_EXCESSIVE, MACSTR
2265 " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
2266 MAC2STR(r->bssid),
2267 wpa_ssid_txt(ssid, ssid_len),
2268 r->freq, r->qual,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002269 r->noise, noise_valid ? "" : "~", r->level,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002270 r->snr, r->snr >= GREAT_SNR ? "*" : "",
2271 r->flags,
2272 r->age, r->est_throughput);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002273 } else {
Sunil Ravia04bd252022-05-02 22:54:18 -07002274 wpa_printf(MSG_EXCESSIVE, MACSTR
2275 " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u",
2276 MAC2STR(r->bssid),
2277 wpa_ssid_txt(ssid, ssid_len),
2278 r->freq, r->qual,
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002279 r->noise, r->level, r->flags, r->age,
2280 r->est_throughput);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002281 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002282 pos = (u8 *) (r + 1);
2283 if (r->ie_len)
2284 wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
2285 pos += r->ie_len;
2286 if (r->beacon_ie_len)
2287 wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
2288 pos, r->beacon_ie_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002289 }
2290#endif /* CONFIG_NO_STDOUT_DEBUG */
2291}
2292
2293
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002294/**
2295 * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed
2296 * @wpa_s: Pointer to wpa_supplicant data
2297 * @bssid: BSSID to check
2298 * Returns: 0 if the BSSID is filtered or 1 if not
2299 *
2300 * This function is used to filter out specific BSSIDs from scan reslts mainly
2301 * for testing purposes (SET bssid_filter ctrl_iface command).
2302 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07002303int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
2304 const u8 *bssid)
2305{
2306 size_t i;
2307
2308 if (wpa_s->bssid_filter == NULL)
2309 return 1;
2310
2311 for (i = 0; i < wpa_s->bssid_filter_count; i++) {
2312 if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
2313 ETH_ALEN) == 0)
2314 return 1;
2315 }
2316
2317 return 0;
2318}
2319
2320
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002321void filter_scan_res(struct wpa_supplicant *wpa_s,
2322 struct wpa_scan_results *res)
Dmitry Shmidt04949592012-07-19 12:16:46 -07002323{
2324 size_t i, j;
2325
2326 if (wpa_s->bssid_filter == NULL)
2327 return;
2328
2329 for (i = 0, j = 0; i < res->num; i++) {
2330 if (wpa_supplicant_filter_bssid_match(wpa_s,
2331 res->res[i]->bssid)) {
2332 res->res[j++] = res->res[i];
2333 } else {
2334 os_free(res->res[i]);
2335 res->res[i] = NULL;
2336 }
2337 }
2338
2339 if (res->num != j) {
2340 wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
2341 (int) (res->num - j));
2342 res->num = j;
2343 }
2344}
2345
2346
Dmitry Shmidt849734c2016-05-27 09:59:01 -07002347void scan_snr(struct wpa_scan_res *res)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002348{
2349 if (res->flags & WPA_SCAN_NOISE_INVALID) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002350 res->noise = is_6ghz_freq(res->freq) ?
2351 DEFAULT_NOISE_FLOOR_6GHZ :
2352 (IS_5GHZ(res->freq) ?
2353 DEFAULT_NOISE_FLOOR_5GHZ : DEFAULT_NOISE_FLOOR_2GHZ);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002354 }
2355
2356 if (res->flags & WPA_SCAN_LEVEL_DBM) {
2357 res->snr = res->level - res->noise;
2358 } else {
2359 /* Level is not in dBm, so we can't calculate
2360 * SNR. Just use raw level (units unknown). */
2361 res->snr = res->level;
2362 }
2363}
2364
2365
Hai Shalom899fcc72020-10-19 14:38:18 -07002366/* Minimum SNR required to achieve a certain bitrate. */
2367struct minsnr_bitrate_entry {
2368 int minsnr;
2369 unsigned int bitrate; /* in Mbps */
2370};
2371
2372/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
2373static const int vht_mcs = 8;
2374
2375static const struct minsnr_bitrate_entry vht20_table[] = {
2376 { 0, 0 },
2377 { 2, 6500 }, /* HT20 MCS0 */
2378 { 5, 13000 }, /* HT20 MCS1 */
2379 { 9, 19500 }, /* HT20 MCS2 */
2380 { 11, 26000 }, /* HT20 MCS3 */
2381 { 15, 39000 }, /* HT20 MCS4 */
2382 { 18, 52000 }, /* HT20 MCS5 */
2383 { 20, 58500 }, /* HT20 MCS6 */
2384 { 25, 65000 }, /* HT20 MCS7 */
2385 { 29, 78000 }, /* VHT20 MCS8 */
2386 { -1, 78000 } /* SNR > 29 */
2387};
2388
2389static const struct minsnr_bitrate_entry vht40_table[] = {
2390 { 0, 0 },
2391 { 5, 13500 }, /* HT40 MCS0 */
2392 { 8, 27000 }, /* HT40 MCS1 */
2393 { 12, 40500 }, /* HT40 MCS2 */
2394 { 14, 54000 }, /* HT40 MCS3 */
2395 { 18, 81000 }, /* HT40 MCS4 */
2396 { 21, 108000 }, /* HT40 MCS5 */
2397 { 23, 121500 }, /* HT40 MCS6 */
2398 { 28, 135000 }, /* HT40 MCS7 */
2399 { 32, 162000 }, /* VHT40 MCS8 */
2400 { 34, 180000 }, /* VHT40 MCS9 */
2401 { -1, 180000 } /* SNR > 34 */
2402};
2403
2404static const struct minsnr_bitrate_entry vht80_table[] = {
2405 { 0, 0 },
2406 { 8, 29300 }, /* VHT80 MCS0 */
2407 { 11, 58500 }, /* VHT80 MCS1 */
2408 { 15, 87800 }, /* VHT80 MCS2 */
2409 { 17, 117000 }, /* VHT80 MCS3 */
2410 { 21, 175500 }, /* VHT80 MCS4 */
2411 { 24, 234000 }, /* VHT80 MCS5 */
2412 { 26, 263300 }, /* VHT80 MCS6 */
2413 { 31, 292500 }, /* VHT80 MCS7 */
2414 { 35, 351000 }, /* VHT80 MCS8 */
2415 { 37, 390000 }, /* VHT80 MCS9 */
2416 { -1, 390000 } /* SNR > 37 */
2417};
2418
2419
Hai Shaloma20dcd72022-02-04 13:43:00 -08002420static const struct minsnr_bitrate_entry vht160_table[] = {
2421 { 0, 0 },
2422 { 11, 58500 }, /* VHT160 MCS0 */
2423 { 14, 117000 }, /* VHT160 MCS1 */
2424 { 18, 175500 }, /* VHT160 MCS2 */
2425 { 20, 234000 }, /* VHT160 MCS3 */
2426 { 24, 351000 }, /* VHT160 MCS4 */
2427 { 27, 468000 }, /* VHT160 MCS5 */
2428 { 29, 526500 }, /* VHT160 MCS6 */
2429 { 34, 585000 }, /* VHT160 MCS7 */
2430 { 38, 702000 }, /* VHT160 MCS8 */
2431 { 40, 780000 }, /* VHT160 MCS9 */
2432 { -1, 780000 } /* SNR > 37 */
2433};
2434
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002435/* EHT needs to be enabled in order to achieve MCS12 and MCS13 rates. */
2436#define EHT_MCS 12
Hai Shaloma20dcd72022-02-04 13:43:00 -08002437
2438static const struct minsnr_bitrate_entry he20_table[] = {
2439 { 0, 0 },
2440 { 2, 8600 }, /* HE20 MCS0 */
2441 { 5, 17200 }, /* HE20 MCS1 */
2442 { 9, 25800 }, /* HE20 MCS2 */
2443 { 11, 34400 }, /* HE20 MCS3 */
2444 { 15, 51600 }, /* HE20 MCS4 */
2445 { 18, 68800 }, /* HE20 MCS5 */
2446 { 20, 77400 }, /* HE20 MCS6 */
2447 { 25, 86000 }, /* HE20 MCS7 */
2448 { 29, 103200 }, /* HE20 MCS8 */
2449 { 31, 114700 }, /* HE20 MCS9 */
2450 { 34, 129000 }, /* HE20 MCS10 */
2451 { 36, 143400 }, /* HE20 MCS11 */
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002452 { 39, 154900 }, /* EHT20 MCS12 */
2453 { 42, 172100 }, /* EHT20 MCS13 */
2454 { -1, 172100 } /* SNR > 42 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002455};
2456
2457static const struct minsnr_bitrate_entry he40_table[] = {
2458 { 0, 0 },
2459 { 5, 17200 }, /* HE40 MCS0 */
2460 { 8, 34400 }, /* HE40 MCS1 */
2461 { 12, 51600 }, /* HE40 MCS2 */
2462 { 14, 68800 }, /* HE40 MCS3 */
2463 { 18, 103200 }, /* HE40 MCS4 */
2464 { 21, 137600 }, /* HE40 MCS5 */
2465 { 23, 154900 }, /* HE40 MCS6 */
2466 { 28, 172100 }, /* HE40 MCS7 */
2467 { 32, 206500 }, /* HE40 MCS8 */
2468 { 34, 229400 }, /* HE40 MCS9 */
2469 { 37, 258100 }, /* HE40 MCS10 */
2470 { 39, 286800 }, /* HE40 MCS11 */
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002471 { 42, 309500 }, /* EHT40 MCS12 */
2472 { 45, 344100 }, /* EHT40 MCS13 */
2473 { -1, 344100 } /* SNR > 45 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002474};
2475
2476static const struct minsnr_bitrate_entry he80_table[] = {
2477 { 0, 0 },
2478 { 8, 36000 }, /* HE80 MCS0 */
2479 { 11, 72100 }, /* HE80 MCS1 */
2480 { 15, 108100 }, /* HE80 MCS2 */
2481 { 17, 144100 }, /* HE80 MCS3 */
2482 { 21, 216200 }, /* HE80 MCS4 */
2483 { 24, 288200 }, /* HE80 MCS5 */
2484 { 26, 324300 }, /* HE80 MCS6 */
2485 { 31, 360300 }, /* HE80 MCS7 */
2486 { 35, 432400 }, /* HE80 MCS8 */
2487 { 37, 480400 }, /* HE80 MCS9 */
2488 { 40, 540400 }, /* HE80 MCS10 */
2489 { 42, 600500 }, /* HE80 MCS11 */
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002490 { 45, 648500 }, /* EHT80 MCS12 */
2491 { 48, 720600 }, /* EHT80 MCS13 */
2492 { -1, 720600 } /* SNR > 48 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002493};
2494
2495
2496static const struct minsnr_bitrate_entry he160_table[] = {
2497 { 0, 0 },
2498 { 11, 72100 }, /* HE160 MCS0 */
2499 { 14, 144100 }, /* HE160 MCS1 */
2500 { 18, 216200 }, /* HE160 MCS2 */
2501 { 20, 288200 }, /* HE160 MCS3 */
2502 { 24, 432400 }, /* HE160 MCS4 */
2503 { 27, 576500 }, /* HE160 MCS5 */
2504 { 29, 648500 }, /* HE160 MCS6 */
2505 { 34, 720600 }, /* HE160 MCS7 */
2506 { 38, 864700 }, /* HE160 MCS8 */
2507 { 40, 960800 }, /* HE160 MCS9 */
2508 { 43, 1080900 }, /* HE160 MCS10 */
2509 { 45, 1201000 }, /* HE160 MCS11 */
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002510 { 48, 1297100 }, /* EHT160 MCS12 */
2511 { 51, 1441200 }, /* EHT160 MCS13 */
2512 { -1, 1441200 } /* SNR > 51 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002513};
2514
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002515/* See IEEE P802.11be/D2.0, Table 36-86: EHT-MCSs for 4x996-tone RU, NSS,u = 1
2516 */
2517static const struct minsnr_bitrate_entry eht320_table[] = {
2518 { 0, 0 },
2519 { 14, 144100 }, /* EHT320 MCS0 */
2520 { 17, 288200 }, /* EHT320 MCS1 */
2521 { 21, 432400 }, /* EHT320 MCS2 */
2522 { 23, 576500 }, /* EHT320 MCS3 */
2523 { 27, 864700 }, /* EHT320 MCS4 */
2524 { 30, 1152900 }, /* EHT320 MCS5 */
2525 { 32, 1297100 }, /* EHT320 MCS6 */
2526 { 37, 1441200 }, /* EHT320 MCS7 */
2527 { 41, 1729400 }, /* EHT320 MCS8 */
2528 { 43, 1921500 }, /* EHT320 MCS9 */
2529 { 46, 2161800 }, /* EHT320 MCS10 */
2530 { 48, 2401900 }, /* EHT320 MCS11 */
2531 { 51, 2594100 }, /* EHT320 MCS12 */
2532 { 54, 2882400 }, /* EHT320 MCS13 */
2533 { -1, 2882400 } /* SNR > 54 */
2534};
Hai Shaloma20dcd72022-02-04 13:43:00 -08002535
Hai Shalomfdcde762020-04-02 11:19:20 -07002536static unsigned int interpolate_rate(int snr, int snr0, int snr1,
2537 int rate0, int rate1)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002538{
Hai Shalomfdcde762020-04-02 11:19:20 -07002539 return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002540}
2541
2542
Hai Shalom899fcc72020-10-19 14:38:18 -07002543static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
2544 int snr, bool vht)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002545{
Hai Shalom899fcc72020-10-19 14:38:18 -07002546 const struct minsnr_bitrate_entry *prev, *entry = table;
2547
2548 while ((entry->minsnr != -1) &&
2549 (snr >= entry->minsnr) &&
2550 (vht || entry - table <= vht_mcs))
2551 entry++;
2552 if (entry == table)
2553 return entry->bitrate;
2554 prev = entry - 1;
2555 if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
2556 return prev->bitrate;
2557 return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
2558 entry->bitrate);
Hai Shalomfdcde762020-04-02 11:19:20 -07002559}
2560
2561
Hai Shalom899fcc72020-10-19 14:38:18 -07002562static unsigned int max_ht20_rate(int snr, bool vht)
Hai Shalomfdcde762020-04-02 11:19:20 -07002563{
Hai Shalom899fcc72020-10-19 14:38:18 -07002564 return max_rate(vht20_table, snr, vht);
2565}
2566
2567
2568static unsigned int max_ht40_rate(int snr, bool vht)
2569{
2570 return max_rate(vht40_table, snr, vht);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002571}
2572
2573
2574static unsigned int max_vht80_rate(int snr)
2575{
Hai Shalom899fcc72020-10-19 14:38:18 -07002576 return max_rate(vht80_table, snr, 1);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002577}
2578
Hai Shalomfdcde762020-04-02 11:19:20 -07002579
Hai Shaloma20dcd72022-02-04 13:43:00 -08002580static unsigned int max_vht160_rate(int snr)
2581{
2582 return max_rate(vht160_table, snr, 1);
2583}
2584
2585
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002586static unsigned int max_he_eht_rate(const struct minsnr_bitrate_entry table[],
2587 int snr, bool eht)
Hai Shaloma20dcd72022-02-04 13:43:00 -08002588{
2589 const struct minsnr_bitrate_entry *prev, *entry = table;
2590
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002591 while (entry->minsnr != -1 && snr >= entry->minsnr &&
2592 (eht || entry - table <= EHT_MCS))
Hai Shaloma20dcd72022-02-04 13:43:00 -08002593 entry++;
2594 if (entry == table)
2595 return 0;
2596 prev = entry - 1;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002597 if (entry->minsnr == -1 || (!eht && entry - table > EHT_MCS))
Hai Shaloma20dcd72022-02-04 13:43:00 -08002598 return prev->bitrate;
2599 return interpolate_rate(snr, prev->minsnr, entry->minsnr,
2600 prev->bitrate, entry->bitrate);
2601}
2602
2603
Hai Shalomfdcde762020-04-02 11:19:20 -07002604unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
2605 const u8 *ies, size_t ies_len, int rate,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002606 int snr, int freq)
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002607{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002608 struct hostapd_hw_modes *hw_mode;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002609 unsigned int est, tmp;
Hai Shalomfdcde762020-04-02 11:19:20 -07002610 const u8 *ie;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002611
2612 /* Limit based on estimated SNR */
2613 if (rate > 1 * 2 && snr < 1)
2614 rate = 1 * 2;
2615 else if (rate > 2 * 2 && snr < 4)
2616 rate = 2 * 2;
2617 else if (rate > 6 * 2 && snr < 5)
2618 rate = 6 * 2;
2619 else if (rate > 9 * 2 && snr < 6)
2620 rate = 9 * 2;
2621 else if (rate > 12 * 2 && snr < 7)
2622 rate = 12 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002623 else if (rate > 12 * 2 && snr < 8)
2624 rate = 14 * 2;
2625 else if (rate > 12 * 2 && snr < 9)
2626 rate = 16 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002627 else if (rate > 18 * 2 && snr < 10)
2628 rate = 18 * 2;
2629 else if (rate > 24 * 2 && snr < 11)
2630 rate = 24 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002631 else if (rate > 24 * 2 && snr < 12)
2632 rate = 27 * 2;
2633 else if (rate > 24 * 2 && snr < 13)
2634 rate = 30 * 2;
2635 else if (rate > 24 * 2 && snr < 14)
2636 rate = 33 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002637 else if (rate > 36 * 2 && snr < 15)
2638 rate = 36 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002639 else if (rate > 36 * 2 && snr < 16)
2640 rate = 39 * 2;
2641 else if (rate > 36 * 2 && snr < 17)
2642 rate = 42 * 2;
2643 else if (rate > 36 * 2 && snr < 18)
2644 rate = 45 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002645 else if (rate > 48 * 2 && snr < 19)
2646 rate = 48 * 2;
Hai Shalomfdcde762020-04-02 11:19:20 -07002647 else if (rate > 48 * 2 && snr < 20)
2648 rate = 51 * 2;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002649 else if (rate > 54 * 2 && snr < 21)
2650 rate = 54 * 2;
2651 est = rate * 500;
2652
Hai Shaloma20dcd72022-02-04 13:43:00 -08002653 hw_mode = get_mode_with_freq(wpa_s->hw.modes, wpa_s->hw.num_modes,
2654 freq);
2655
2656 if (hw_mode && hw_mode->ht_capab) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002657 ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002658 if (ie) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002659 tmp = max_ht20_rate(snr, false);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002660 if (tmp > est)
2661 est = tmp;
2662 }
2663 }
2664
Hai Shaloma20dcd72022-02-04 13:43:00 -08002665 if (hw_mode &&
2666 (hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002667 ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002668 if (ie && ie[1] >= 2 &&
2669 (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002670 tmp = max_ht40_rate(snr, false);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002671 if (tmp > est)
2672 est = tmp;
2673 }
2674 }
2675
Hai Shaloma20dcd72022-02-04 13:43:00 -08002676 if (hw_mode && hw_mode->vht_capab) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002677 /* Use +1 to assume VHT is always faster than HT */
Hai Shalomfdcde762020-04-02 11:19:20 -07002678 ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002679 if (ie) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002680 bool vht80 = false, vht160 = false;
2681
Hai Shalom899fcc72020-10-19 14:38:18 -07002682 tmp = max_ht20_rate(snr, true) + 1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002683 if (tmp > est)
2684 est = tmp;
2685
Hai Shalomfdcde762020-04-02 11:19:20 -07002686 ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002687 if (ie && ie[1] >= 2 &&
2688 (ie[3] &
2689 HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002690 tmp = max_ht40_rate(snr, true) + 1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002691 if (tmp > est)
2692 est = tmp;
2693 }
2694
Hai Shaloma20dcd72022-02-04 13:43:00 -08002695 /* Determine VHT BSS bandwidth based on IEEE Std
2696 * 802.11-2020, Table 11-23 (VHT BSs bandwidth) */
Hai Shalomfdcde762020-04-02 11:19:20 -07002697 ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002698 if (ie && ie[1] >= 3) {
2699 u8 cw = ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK;
2700 u8 seg0 = ie[3];
2701 u8 seg1 = ie[4];
2702
2703 if (cw)
2704 vht80 = true;
2705 if (cw == 2 ||
2706 (cw == 3 &&
2707 (seg1 > 0 && abs(seg1 - seg0) == 16)))
2708 vht160 = true;
2709 if (cw == 1 &&
2710 ((seg1 > 0 && abs(seg1 - seg0) == 8) ||
2711 (seg1 > 0 && abs(seg1 - seg0) == 16)))
2712 vht160 = true;
2713 }
2714
2715 if (vht80) {
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002716 tmp = max_vht80_rate(snr) + 1;
2717 if (tmp > est)
2718 est = tmp;
2719 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002720
2721 if (vht160 &&
2722 (hw_mode->vht_capab &
2723 (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
2724 VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
2725 tmp = max_vht160_rate(snr) + 1;
2726 if (tmp > est)
2727 est = tmp;
2728 }
2729 }
2730 }
2731
2732 if (hw_mode && hw_mode->he_capab[IEEE80211_MODE_INFRA].he_supported) {
2733 /* Use +2 to assume HE is always faster than HT/VHT */
2734 struct ieee80211_he_capabilities *he;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002735 struct ieee80211_eht_capabilities *eht;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002736 struct he_capabilities *own_he;
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002737 u8 cw, boost = 2;
2738 const u8 *eht_ie;
2739 bool is_eht = false;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002740
2741 ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES);
2742 if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN))
2743 return est;
2744 he = (struct ieee80211_he_capabilities *) &ie[3];
2745 own_he = &hw_mode->he_capab[IEEE80211_MODE_INFRA];
2746
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002747 /* Use +3 to assume EHT is always faster than HE */
2748 if (hw_mode->eht_capab[IEEE80211_MODE_INFRA].eht_supported) {
2749 eht_ie = get_ie_ext(ies, ies_len,
2750 WLAN_EID_EXT_EHT_CAPABILITIES);
2751 if (eht_ie &&
2752 (eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN)) {
2753 is_eht = true;
2754 boost = 3;
2755 }
2756 }
2757
2758 tmp = max_he_eht_rate(he20_table, snr, is_eht) + boost;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002759 if (tmp > est)
2760 est = tmp;
2761
2762 cw = he->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
2763 own_he->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
2764 if (cw &
2765 (IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G :
2766 HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002767 tmp = max_he_eht_rate(he40_table, snr, is_eht) + boost;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002768 if (tmp > est)
2769 est = tmp;
2770 }
2771
2772 if (!IS_2P4GHZ(freq) &&
2773 (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002774 tmp = max_he_eht_rate(he80_table, snr, is_eht) + boost;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002775 if (tmp > est)
2776 est = tmp;
2777 }
2778
2779 if (!IS_2P4GHZ(freq) &&
2780 (cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
2781 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) {
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00002782 tmp = max_he_eht_rate(he160_table, snr, is_eht) + boost;
2783 if (tmp > est)
2784 est = tmp;
2785 }
2786
2787 if (!is_eht)
2788 return est;
2789
2790 eht = (struct ieee80211_eht_capabilities *) &eht_ie[3];
2791
2792 if (is_6ghz_freq(freq) &&
2793 (eht->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
2794 EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
2795 tmp = max_he_eht_rate(eht320_table, snr, true);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002796 if (tmp > est)
2797 est = tmp;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002798 }
2799 }
2800
Hai Shalomfdcde762020-04-02 11:19:20 -07002801 return est;
2802}
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002803
Hai Shalomfdcde762020-04-02 11:19:20 -07002804
2805void scan_est_throughput(struct wpa_supplicant *wpa_s,
2806 struct wpa_scan_res *res)
2807{
2808 int rate; /* max legacy rate in 500 kb/s units */
2809 int snr = res->snr;
2810 const u8 *ies = (const void *) (res + 1);
2811 size_t ie_len = res->ie_len;
2812
2813 if (res->est_throughput)
2814 return;
2815
2816 /* Get maximum legacy rate */
2817 rate = wpa_scan_get_max_rate(res);
2818
2819 if (!ie_len)
2820 ie_len = res->beacon_ie_len;
2821 res->est_throughput =
Hai Shaloma20dcd72022-02-04 13:43:00 -08002822 wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, res->freq);
Hai Shalomfdcde762020-04-02 11:19:20 -07002823
2824 /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002825}
2826
2827
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002828/**
2829 * wpa_supplicant_get_scan_results - Get scan results
2830 * @wpa_s: Pointer to wpa_supplicant data
2831 * @info: Information about what was scanned or %NULL if not available
2832 * @new_scan: Whether a new scan was performed
2833 * Returns: Scan results, %NULL on failure
2834 *
2835 * This function request the current scan results from the driver and updates
2836 * the local BSS list wpa_s->bss. The caller is responsible for freeing the
2837 * results with wpa_scan_results_free().
2838 */
2839struct wpa_scan_results *
2840wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
2841 struct scan_info *info, int new_scan)
2842{
2843 struct wpa_scan_results *scan_res;
2844 size_t i;
2845 int (*compar)(const void *, const void *) = wpa_scan_result_compar;
2846
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002847 scan_res = wpa_drv_get_scan_results2(wpa_s);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002848 if (scan_res == NULL) {
2849 wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
2850 return NULL;
2851 }
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002852 if (scan_res->fetch_time.sec == 0) {
2853 /*
2854 * Make sure we have a valid timestamp if the driver wrapper
2855 * does not set this.
2856 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002857 os_get_reltime(&scan_res->fetch_time);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002858 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002859 filter_scan_res(wpa_s, scan_res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002860
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002861 for (i = 0; i < scan_res->num; i++) {
2862 struct wpa_scan_res *scan_res_item = scan_res->res[i];
2863
Dmitry Shmidt7f656022015-02-25 14:36:37 -08002864 scan_snr(scan_res_item);
2865 scan_est_throughput(wpa_s, scan_res_item);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002866 }
2867
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002868#ifdef CONFIG_WPS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002869 if (wpas_wps_searching(wpa_s)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002870 wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
2871 "provisioning rules");
2872 compar = wpa_scan_result_wps_compar;
2873 }
2874#endif /* CONFIG_WPS */
2875
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002876 if (scan_res->res) {
2877 qsort(scan_res->res, scan_res->num,
2878 sizeof(struct wpa_scan_res *), compar);
2879 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002880 dump_scan_res(scan_res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002881
Dmitry Shmidt29333592017-01-09 12:27:11 -08002882 if (wpa_s->ignore_post_flush_scan_res) {
2883 /* FLUSH command aborted an ongoing scan and these are the
2884 * results from the aborted scan. Do not process the results to
2885 * maintain flushed state. */
2886 wpa_dbg(wpa_s, MSG_DEBUG,
2887 "Do not update BSS table based on pending post-FLUSH scan results");
2888 wpa_s->ignore_post_flush_scan_res = 0;
2889 return scan_res;
2890 }
2891
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002892 wpa_bss_update_start(wpa_s);
2893 for (i = 0; i < scan_res->num; i++)
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002894 wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
2895 &scan_res->fetch_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002896 wpa_bss_update_end(wpa_s, info, new_scan);
2897
2898 return scan_res;
2899}
2900
2901
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002902/**
2903 * wpa_supplicant_update_scan_results - Update scan results from the driver
2904 * @wpa_s: Pointer to wpa_supplicant data
2905 * Returns: 0 on success, -1 on failure
2906 *
2907 * This function updates the BSS table within wpa_supplicant based on the
2908 * currently available scan results from the driver without requesting a new
2909 * scan. This is used in cases where the driver indicates an association
2910 * (including roaming within ESS) and wpa_supplicant does not yet have the
2911 * needed information to complete the connection (e.g., to perform validation
2912 * steps in 4-way handshake).
2913 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002914int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
2915{
2916 struct wpa_scan_results *scan_res;
2917 scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
2918 if (scan_res == NULL)
2919 return -1;
2920 wpa_scan_results_free(scan_res);
2921
2922 return 0;
2923}
Dmitry Shmidt3a787e62013-01-17 10:32:35 -08002924
2925
2926/**
2927 * scan_only_handler - Reports scan results
2928 */
2929void scan_only_handler(struct wpa_supplicant *wpa_s,
2930 struct wpa_scan_results *scan_res)
2931{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002932 wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002933 if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
2934 wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
2935 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
2936 wpa_s->manual_scan_id);
2937 wpa_s->manual_scan_use_id = 0;
2938 } else {
2939 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
2940 }
Dmitry Shmidt3a787e62013-01-17 10:32:35 -08002941 wpas_notify_scan_results(wpa_s);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08002942 wpas_notify_scan_done(wpa_s, 1);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002943 if (wpa_s->scan_work) {
2944 struct wpa_radio_work *work = wpa_s->scan_work;
2945 wpa_s->scan_work = NULL;
2946 radio_work_done(work);
2947 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002948
2949 if (wpa_s->wpa_state == WPA_SCANNING)
2950 wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
Dmitry Shmidt3a787e62013-01-17 10:32:35 -08002951}
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -07002952
2953
2954int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
2955{
2956 return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
2957}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002958
2959
2960struct wpa_driver_scan_params *
2961wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
2962{
2963 struct wpa_driver_scan_params *params;
2964 size_t i;
2965 u8 *n;
2966
2967 params = os_zalloc(sizeof(*params));
2968 if (params == NULL)
2969 return NULL;
2970
2971 for (i = 0; i < src->num_ssids; i++) {
2972 if (src->ssids[i].ssid) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002973 n = os_memdup(src->ssids[i].ssid,
2974 src->ssids[i].ssid_len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002975 if (n == NULL)
2976 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002977 params->ssids[i].ssid = n;
2978 params->ssids[i].ssid_len = src->ssids[i].ssid_len;
2979 }
2980 }
2981 params->num_ssids = src->num_ssids;
2982
2983 if (src->extra_ies) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002984 n = os_memdup(src->extra_ies, src->extra_ies_len);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002985 if (n == NULL)
2986 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002987 params->extra_ies = n;
2988 params->extra_ies_len = src->extra_ies_len;
2989 }
2990
2991 if (src->freqs) {
2992 int len = int_array_len(src->freqs);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002993 params->freqs = os_memdup(src->freqs, (len + 1) * sizeof(int));
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002994 if (params->freqs == NULL)
2995 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002996 }
2997
2998 if (src->filter_ssids) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002999 params->filter_ssids = os_memdup(src->filter_ssids,
3000 sizeof(*params->filter_ssids) *
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003001 src->num_filter_ssids);
3002 if (params->filter_ssids == NULL)
3003 goto failed;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003004 params->num_filter_ssids = src->num_filter_ssids;
3005 }
3006
3007 params->filter_rssi = src->filter_rssi;
3008 params->p2p_probe = src->p2p_probe;
3009 params->only_new_results = src->only_new_results;
Dmitry Shmidt2271d3f2014-06-23 12:16:31 -07003010 params->low_priority = src->low_priority;
Dmitry Shmidt29333592017-01-09 12:27:11 -08003011 params->duration = src->duration;
3012 params->duration_mandatory = src->duration_mandatory;
Hai Shalomce48b4a2018-09-05 11:41:35 -07003013 params->oce_scan = src->oce_scan;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003014
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003015 if (src->sched_scan_plans_num > 0) {
3016 params->sched_scan_plans =
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003017 os_memdup(src->sched_scan_plans,
3018 sizeof(*src->sched_scan_plans) *
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003019 src->sched_scan_plans_num);
3020 if (!params->sched_scan_plans)
3021 goto failed;
3022
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003023 params->sched_scan_plans_num = src->sched_scan_plans_num;
3024 }
3025
Hai Shalomc3565922019-10-28 11:58:20 -07003026 if (src->mac_addr_rand &&
3027 wpa_setup_mac_addr_rand_params(params, src->mac_addr))
3028 goto failed;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003029
3030 if (src->bssid) {
3031 u8 *bssid;
3032
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003033 bssid = os_memdup(src->bssid, ETH_ALEN);
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003034 if (!bssid)
3035 goto failed;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003036 params->bssid = bssid;
3037 }
3038
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003039 params->relative_rssi_set = src->relative_rssi_set;
3040 params->relative_rssi = src->relative_rssi;
3041 params->relative_adjust_band = src->relative_adjust_band;
3042 params->relative_adjust_rssi = src->relative_adjust_rssi;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003043 params->p2p_include_6ghz = src->p2p_include_6ghz;
Sunil8cd6f4d2022-06-28 18:40:46 +00003044 params->non_coloc_6ghz = src->non_coloc_6ghz;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003045 return params;
3046
3047failed:
3048 wpa_scan_free_params(params);
3049 return NULL;
3050}
3051
3052
3053void wpa_scan_free_params(struct wpa_driver_scan_params *params)
3054{
3055 size_t i;
3056
3057 if (params == NULL)
3058 return;
3059
3060 for (i = 0; i < params->num_ssids; i++)
3061 os_free((u8 *) params->ssids[i].ssid);
3062 os_free((u8 *) params->extra_ies);
3063 os_free(params->freqs);
3064 os_free(params->filter_ssids);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003065 os_free(params->sched_scan_plans);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003066
3067 /*
3068 * Note: params->mac_addr_mask points to same memory allocation and
3069 * must not be freed separately.
3070 */
3071 os_free((u8 *) params->mac_addr);
3072
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003073 os_free((u8 *) params->bssid);
3074
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003075 os_free(params);
3076}
Dmitry Shmidt98660862014-03-11 17:26:21 -07003077
3078
3079int wpas_start_pno(struct wpa_supplicant *wpa_s)
3080{
Hai Shalomfdcde762020-04-02 11:19:20 -07003081 int ret;
3082 size_t prio, i, num_ssid, num_match_ssid;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003083 struct wpa_ssid *ssid;
3084 struct wpa_driver_scan_params params;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003085 struct sched_scan_plan scan_plan;
Dmitry Shmidte4663042016-04-04 10:07:49 -07003086 unsigned int max_sched_scan_ssids;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003087
3088 if (!wpa_s->sched_scan_supported)
3089 return -1;
3090
Dmitry Shmidte4663042016-04-04 10:07:49 -07003091 if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
3092 max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
3093 else
3094 max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
3095 if (max_sched_scan_ssids < 1)
3096 return -1;
3097
Dmitry Shmidt98660862014-03-11 17:26:21 -07003098 if (wpa_s->pno || wpa_s->pno_sched_pending)
3099 return 0;
3100
3101 if ((wpa_s->wpa_state > WPA_SCANNING) &&
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003102 (wpa_s->wpa_state < WPA_COMPLETED)) {
Dmitry Shmidt98660862014-03-11 17:26:21 -07003103 wpa_printf(MSG_ERROR, "PNO: In assoc process");
3104 return -EAGAIN;
3105 }
3106
3107 if (wpa_s->wpa_state == WPA_SCANNING) {
3108 wpa_supplicant_cancel_scan(wpa_s);
3109 if (wpa_s->sched_scanning) {
3110 wpa_printf(MSG_DEBUG, "Schedule PNO on completion of "
3111 "ongoing sched scan");
3112 wpa_supplicant_cancel_sched_scan(wpa_s);
3113 wpa_s->pno_sched_pending = 1;
3114 return 0;
3115 }
3116 }
3117
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003118 if (wpa_s->sched_scan_stop_req) {
3119 wpa_printf(MSG_DEBUG,
3120 "Schedule PNO after previous sched scan has stopped");
3121 wpa_s->pno_sched_pending = 1;
3122 return 0;
3123 }
3124
Dmitry Shmidt98660862014-03-11 17:26:21 -07003125 os_memset(&params, 0, sizeof(params));
3126
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003127 num_ssid = num_match_ssid = 0;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003128 ssid = wpa_s->conf->ssid;
3129 while (ssid) {
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003130 if (!wpas_network_disabled(wpa_s, ssid)) {
3131 num_match_ssid++;
3132 if (ssid->scan_ssid)
3133 num_ssid++;
3134 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003135 ssid = ssid->next;
3136 }
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003137
3138 if (num_match_ssid == 0) {
3139 wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
3140 return -1;
3141 }
3142
3143 if (num_match_ssid > num_ssid) {
3144 params.num_ssids++; /* wildcard */
3145 num_ssid++;
3146 }
3147
Dmitry Shmidte4663042016-04-04 10:07:49 -07003148 if (num_ssid > max_sched_scan_ssids) {
Dmitry Shmidt98660862014-03-11 17:26:21 -07003149 wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
Dmitry Shmidte4663042016-04-04 10:07:49 -07003150 "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
3151 num_ssid = max_sched_scan_ssids;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003152 }
3153
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003154 if (num_match_ssid > wpa_s->max_match_sets) {
3155 num_match_ssid = wpa_s->max_match_sets;
3156 wpa_dbg(wpa_s, MSG_DEBUG, "PNO: Too many SSIDs to match");
Dmitry Shmidt98660862014-03-11 17:26:21 -07003157 }
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003158 params.filter_ssids = os_calloc(num_match_ssid,
3159 sizeof(struct wpa_driver_scan_filter));
Dmitry Shmidt98660862014-03-11 17:26:21 -07003160 if (params.filter_ssids == NULL)
3161 return -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003162
Dmitry Shmidt98660862014-03-11 17:26:21 -07003163 i = 0;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003164 prio = 0;
3165 ssid = wpa_s->conf->pssid[prio];
Dmitry Shmidt98660862014-03-11 17:26:21 -07003166 while (ssid) {
3167 if (!wpas_network_disabled(wpa_s, ssid)) {
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003168 if (ssid->scan_ssid && params.num_ssids < num_ssid) {
3169 params.ssids[params.num_ssids].ssid =
3170 ssid->ssid;
3171 params.ssids[params.num_ssids].ssid_len =
3172 ssid->ssid_len;
3173 params.num_ssids++;
3174 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003175 os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
3176 ssid->ssid_len);
3177 params.filter_ssids[i].ssid_len = ssid->ssid_len;
3178 params.num_filter_ssids++;
3179 i++;
Dmitry Shmidt6aa8ae42014-07-07 09:31:33 -07003180 if (i == num_match_ssid)
Dmitry Shmidt98660862014-03-11 17:26:21 -07003181 break;
3182 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -08003183 if (ssid->pnext)
3184 ssid = ssid->pnext;
3185 else if (prio + 1 == wpa_s->conf->num_prio)
3186 break;
3187 else
3188 ssid = wpa_s->conf->pssid[++prio];
Dmitry Shmidt98660862014-03-11 17:26:21 -07003189 }
3190
3191 if (wpa_s->conf->filter_rssi)
3192 params.filter_rssi = wpa_s->conf->filter_rssi;
3193
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003194 if (wpa_s->sched_scan_plans_num) {
3195 params.sched_scan_plans = wpa_s->sched_scan_plans;
3196 params.sched_scan_plans_num = wpa_s->sched_scan_plans_num;
3197 } else {
3198 /* Set one scan plan that will run infinitely */
3199 if (wpa_s->conf->sched_scan_interval)
3200 scan_plan.interval = wpa_s->conf->sched_scan_interval;
3201 else
3202 scan_plan.interval = 10;
3203
3204 scan_plan.iterations = 0;
3205 params.sched_scan_plans = &scan_plan;
3206 params.sched_scan_plans_num = 1;
3207 }
Dmitry Shmidt98660862014-03-11 17:26:21 -07003208
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003209 params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay;
3210
Dmitry Shmidtd11f0192014-03-24 12:09:47 -07003211 if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) {
3212 wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels");
3213 params.freqs = wpa_s->manual_sched_scan_freqs;
3214 }
3215
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003216 if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
Hai Shalomc3565922019-10-28 11:58:20 -07003217 wpa_s->wpa_state <= WPA_SCANNING)
3218 wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_pno);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003219
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08003220 wpa_scan_set_relative_rssi_params(wpa_s, &params);
3221
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003222 ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
Dmitry Shmidt98660862014-03-11 17:26:21 -07003223 os_free(params.filter_ssids);
Hai Shalomc3565922019-10-28 11:58:20 -07003224 os_free(params.mac_addr);
Dmitry Shmidt98660862014-03-11 17:26:21 -07003225 if (ret == 0)
3226 wpa_s->pno = 1;
3227 else
3228 wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO");
3229 return ret;
3230}
3231
3232
3233int wpas_stop_pno(struct wpa_supplicant *wpa_s)
3234{
3235 int ret = 0;
3236
3237 if (!wpa_s->pno)
3238 return 0;
3239
3240 ret = wpa_supplicant_stop_sched_scan(wpa_s);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003241 wpa_s->sched_scan_stop_req = 1;
Dmitry Shmidt98660862014-03-11 17:26:21 -07003242
3243 wpa_s->pno = 0;
3244 wpa_s->pno_sched_pending = 0;
3245
3246 if (wpa_s->wpa_state == WPA_SCANNING)
3247 wpa_supplicant_req_scan(wpa_s, 0, 0);
3248
3249 return ret;
3250}
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003251
3252
3253void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
3254 unsigned int type)
3255{
3256 type &= MAC_ADDR_RAND_ALL;
3257 wpa_s->mac_addr_rand_enable &= ~type;
3258
3259 if (type & MAC_ADDR_RAND_SCAN) {
3260 os_free(wpa_s->mac_addr_scan);
3261 wpa_s->mac_addr_scan = NULL;
3262 }
3263
3264 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
3265 os_free(wpa_s->mac_addr_sched_scan);
3266 wpa_s->mac_addr_sched_scan = NULL;
3267 }
3268
3269 if (type & MAC_ADDR_RAND_PNO) {
3270 os_free(wpa_s->mac_addr_pno);
3271 wpa_s->mac_addr_pno = NULL;
3272 }
3273}
3274
3275
3276int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
3277 unsigned int type, const u8 *addr,
3278 const u8 *mask)
3279{
3280 u8 *tmp = NULL;
3281
Hai Shalom74f70d42019-02-11 14:42:39 -08003282 if ((wpa_s->mac_addr_rand_supported & type) != type ) {
3283 wpa_printf(MSG_INFO,
3284 "scan: MAC randomization type %u != supported=%u",
3285 type, wpa_s->mac_addr_rand_supported);
3286 return -1;
3287 }
3288
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003289 wpas_mac_addr_rand_scan_clear(wpa_s, type);
3290
3291 if (addr) {
3292 tmp = os_malloc(2 * ETH_ALEN);
3293 if (!tmp)
3294 return -1;
3295 os_memcpy(tmp, addr, ETH_ALEN);
3296 os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN);
3297 }
3298
3299 if (type == MAC_ADDR_RAND_SCAN) {
3300 wpa_s->mac_addr_scan = tmp;
3301 } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
3302 wpa_s->mac_addr_sched_scan = tmp;
3303 } else if (type == MAC_ADDR_RAND_PNO) {
3304 wpa_s->mac_addr_pno = tmp;
3305 } else {
3306 wpa_printf(MSG_INFO,
3307 "scan: Invalid MAC randomization type=0x%x",
3308 type);
3309 os_free(tmp);
3310 return -1;
3311 }
3312
3313 wpa_s->mac_addr_rand_enable |= type;
3314 return 0;
3315}
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003316
3317
Hai Shalomc3565922019-10-28 11:58:20 -07003318int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
3319 unsigned int type, u8 *mask)
3320{
3321 const u8 *to_copy;
3322
3323 if ((wpa_s->mac_addr_rand_enable & type) != type)
3324 return -1;
3325
3326 if (type == MAC_ADDR_RAND_SCAN) {
3327 to_copy = wpa_s->mac_addr_scan;
3328 } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
3329 to_copy = wpa_s->mac_addr_sched_scan;
3330 } else if (type == MAC_ADDR_RAND_PNO) {
3331 to_copy = wpa_s->mac_addr_pno;
3332 } else {
3333 wpa_printf(MSG_DEBUG,
3334 "scan: Invalid MAC randomization type=0x%x",
3335 type);
3336 return -1;
3337 }
3338
3339 os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
3340 return 0;
3341}
3342
3343
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003344int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
3345{
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003346 struct wpa_radio_work *work;
3347 struct wpa_radio *radio = wpa_s->radio;
Dmitry Shmidt9c175262016-03-03 10:20:07 -08003348
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003349 dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
3350 if (work->wpa_s != wpa_s || !work->started ||
3351 (os_strcmp(work->type, "scan") != 0 &&
3352 os_strcmp(work->type, "p2p-scan") != 0))
3353 continue;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003354 wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003355 return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003356 }
3357
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08003358 wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort");
3359 return -1;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003360}
3361
3362
3363int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd)
3364{
3365 struct sched_scan_plan *scan_plans = NULL;
3366 const char *token, *context = NULL;
3367 unsigned int num = 0;
3368
3369 if (!cmd)
3370 return -1;
3371
3372 if (!cmd[0]) {
3373 wpa_printf(MSG_DEBUG, "Clear sched scan plans");
3374 os_free(wpa_s->sched_scan_plans);
3375 wpa_s->sched_scan_plans = NULL;
3376 wpa_s->sched_scan_plans_num = 0;
3377 return 0;
3378 }
3379
3380 while ((token = cstr_token(cmd, " ", &context))) {
3381 int ret;
3382 struct sched_scan_plan *scan_plan, *n;
3383
3384 n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans));
3385 if (!n)
3386 goto fail;
3387
3388 scan_plans = n;
3389 scan_plan = &scan_plans[num];
3390 num++;
3391
3392 ret = sscanf(token, "%u:%u", &scan_plan->interval,
3393 &scan_plan->iterations);
3394 if (ret <= 0 || ret > 2 || !scan_plan->interval) {
3395 wpa_printf(MSG_ERROR,
3396 "Invalid sched scan plan input: %s", token);
3397 goto fail;
3398 }
3399
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08003400 if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
3401 wpa_printf(MSG_WARNING,
3402 "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
3403 num, scan_plan->interval,
3404 wpa_s->max_sched_scan_plan_interval);
3405 scan_plan->interval =
3406 wpa_s->max_sched_scan_plan_interval;
3407 }
3408
3409 if (ret == 1) {
3410 scan_plan->iterations = 0;
3411 break;
3412 }
3413
3414 if (!scan_plan->iterations) {
3415 wpa_printf(MSG_ERROR,
3416 "scan plan %u: Number of iterations cannot be zero",
3417 num);
3418 goto fail;
3419 }
3420
3421 if (scan_plan->iterations >
3422 wpa_s->max_sched_scan_plan_iterations) {
3423 wpa_printf(MSG_WARNING,
3424 "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)",
3425 num, scan_plan->iterations,
3426 wpa_s->max_sched_scan_plan_iterations);
3427 scan_plan->iterations =
3428 wpa_s->max_sched_scan_plan_iterations;
3429 }
3430
3431 wpa_printf(MSG_DEBUG,
3432 "scan plan %u: interval=%u iterations=%u",
3433 num, scan_plan->interval, scan_plan->iterations);
3434 }
3435
3436 if (!scan_plans) {
3437 wpa_printf(MSG_ERROR, "Invalid scan plans entry");
3438 goto fail;
3439 }
3440
3441 if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) {
3442 wpa_printf(MSG_ERROR,
3443 "All scan plans but the last must specify a number of iterations");
3444 goto fail;
3445 }
3446
3447 wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u",
3448 num, scan_plans[num - 1].interval);
3449
3450 if (num > wpa_s->max_sched_scan_plans) {
3451 wpa_printf(MSG_WARNING,
3452 "Too many scheduled scan plans (only %u supported)",
3453 wpa_s->max_sched_scan_plans);
3454 wpa_printf(MSG_WARNING,
3455 "Use only the first %u scan plans, and the last one (in infinite loop)",
3456 wpa_s->max_sched_scan_plans - 1);
3457 os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1],
3458 &scan_plans[num - 1], sizeof(*scan_plans));
3459 num = wpa_s->max_sched_scan_plans;
3460 }
3461
3462 os_free(wpa_s->sched_scan_plans);
3463 wpa_s->sched_scan_plans = scan_plans;
3464 wpa_s->sched_scan_plans_num = num;
3465
3466 return 0;
3467
3468fail:
3469 os_free(scan_plans);
3470 wpa_printf(MSG_ERROR, "invalid scan plans list");
3471 return -1;
3472}
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07003473
3474
3475/**
3476 * wpas_scan_reset_sched_scan - Reset sched_scan state
3477 * @wpa_s: Pointer to wpa_supplicant data
3478 *
3479 * This function is used to cancel a running scheduled scan and to reset an
3480 * internal scan state to continue with a regular scan on the following
3481 * wpa_supplicant_req_scan() calls.
3482 */
3483void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s)
3484{
3485 wpa_s->normal_scans = 0;
3486 if (wpa_s->sched_scanning) {
3487 wpa_s->sched_scan_timed_out = 0;
3488 wpa_s->prev_sched_ssid = NULL;
3489 wpa_supplicant_cancel_sched_scan(wpa_s);
3490 }
3491}
3492
3493
3494void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s)
3495{
3496 /* simulate timeout to restart the sched scan */
3497 wpa_s->sched_scan_timed_out = 1;
3498 wpa_s->prev_sched_ssid = NULL;
3499 wpa_supplicant_cancel_sched_scan(wpa_s);
3500}