| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * WPA Supplicant - Scanning | 
| Hai Shalom | 021b0b5 | 2019-04-10 11:17:58 -0700 | [diff] [blame] | 3 | * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 4 | * | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 5 | * This software may be distributed under the terms of the BSD license. | 
|  | 6 | * See README for more details. | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 7 | */ | 
|  | 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 Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 14 | #include "common/wpa_ctrl.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 15 | #include "config.h" | 
|  | 16 | #include "wpa_supplicant_i.h" | 
|  | 17 | #include "driver_i.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 18 | #include "wps_supplicant.h" | 
|  | 19 | #include "p2p_supplicant.h" | 
|  | 20 | #include "p2p/p2p.h" | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 21 | #include "hs20_supplicant.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 22 | #include "notify.h" | 
|  | 23 | #include "bss.h" | 
|  | 24 | #include "scan.h" | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 25 | #include "mesh.h" | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 26 |  | 
|  | 27 |  | 
|  | 28 | static 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 Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 39 | wpas_notify_network_changed(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 40 | } | 
|  | 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 Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 50 | static int wpas_wps_in_use(struct wpa_supplicant *wpa_s, | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 51 | enum wps_request_type *req_type) | 
|  | 52 | { | 
|  | 53 | struct wpa_ssid *ssid; | 
|  | 54 | int wps = 0; | 
|  | 55 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 56 | for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 57 | if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) | 
|  | 58 | continue; | 
|  | 59 |  | 
|  | 60 | wps = 1; | 
|  | 61 | *req_type = wpas_wps_get_req_type(ssid); | 
| Dmitry Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 62 | if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1")) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 63 | return 2; | 
|  | 64 | } | 
|  | 65 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 66 | #ifdef CONFIG_P2P | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 67 | if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p && | 
|  | 68 | !wpa_s->conf->p2p_disabled) { | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 69 | wpa_s->wps->dev.p2p = 1; | 
|  | 70 | if (!wps) { | 
|  | 71 | wps = 1; | 
|  | 72 | *req_type = WPS_REQ_ENROLLEE_INFO; | 
|  | 73 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 74 | } | 
|  | 75 | #endif /* CONFIG_P2P */ | 
|  | 76 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 77 | return wps; | 
|  | 78 | } | 
|  | 79 | #endif /* CONFIG_WPS */ | 
|  | 80 |  | 
|  | 81 |  | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 82 | static 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 Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 109 | /** | 
|  | 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 Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 118 | int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 119 | { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 120 | struct wpa_ssid *ssid = wpa_s->conf->ssid; | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 121 | int count = 0, disabled = 0; | 
| Dmitry Shmidt | 203eadb | 2015-03-05 14:16:04 -0800 | [diff] [blame] | 122 |  | 
|  | 123 | if (wpa_s->p2p_mgmt) | 
|  | 124 | return 0; /* no normal network profiles on p2p_mgmt interface */ | 
|  | 125 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 126 | while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 127 | if (!wpas_network_disabled(wpa_s, ssid)) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 128 | count++; | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 129 | else | 
|  | 130 | disabled++; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 131 | ssid = ssid->next; | 
|  | 132 | } | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 133 | if (wpa_s->conf->cred && wpa_s->conf->interworking && | 
|  | 134 | wpa_s->conf->auto_interworking) | 
|  | 135 | count++; | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 136 | if (count == 0 && disabled > 0) { | 
|  | 137 | wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled " | 
|  | 138 | "networks)", disabled); | 
|  | 139 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 140 | return count; | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 |  | 
|  | 144 | static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, | 
|  | 145 | struct wpa_ssid *ssid) | 
|  | 146 | { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 147 | int min_temp_disabled = 0; | 
|  | 148 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 149 | while (ssid) { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 150 | 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 Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 160 | 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 Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 168 | wpa_supplicant_req_scan(wpa_s, min_temp_disabled, 0); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 169 | 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 Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 182 | static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 183 | { | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 184 | struct wpa_supplicant *wpa_s = work->wpa_s; | 
|  | 185 | struct wpa_driver_scan_params *params = work->ctx; | 
|  | 186 | int ret; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 187 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 188 | if (deinit) { | 
| Dmitry Shmidt | bd14a57 | 2014-02-18 10:33:49 -0800 | [diff] [blame] | 189 | 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 Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 196 | return; | 
|  | 197 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 198 |  | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 199 | 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 Shmidt | 661b4f7 | 2014-09-29 14:58:27 -0700 | [diff] [blame] | 203 | 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 Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 206 | wpa_scan_free_params(params); | 
|  | 207 | wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); | 
| Dmitry Shmidt | 661b4f7 | 2014-09-29 14:58:27 -0700 | [diff] [blame] | 208 | radio_work_done(work); | 
|  | 209 | return; | 
|  | 210 | } | 
|  | 211 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 212 | wpa_supplicant_notify_scanning(wpa_s, 1); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 213 |  | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 214 | 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 Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 217 | params->only_new_results = 1; | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 218 | } | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 219 | ret = wpa_drv_scan(wpa_s, params); | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 220 | /* | 
|  | 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 Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 231 | wpa_scan_free_params(params); | 
|  | 232 | work->ctx = NULL; | 
|  | 233 | if (ret) { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 234 | int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ && | 
|  | 235 | !wpa_s->beacon_rep_data.token; | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 236 |  | 
|  | 237 | if (wpa_s->disconnected) | 
|  | 238 | retry = 0; | 
|  | 239 |  | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 240 | /* do not retry if operation is not supported */ | 
|  | 241 | if (ret == -EOPNOTSUPP) | 
|  | 242 | retry = 0; | 
|  | 243 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 244 | wpa_supplicant_notify_scanning(wpa_s, 0); | 
|  | 245 | wpas_notify_scan_done(wpa_s, 0); | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 246 | 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 Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 251 | radio_work_done(work); | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 252 |  | 
|  | 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 Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 257 | } else if (wpa_s->scan_res_handler) { | 
|  | 258 | /* Clear the scan_res_handler */ | 
|  | 259 | wpa_s->scan_res_handler = NULL; | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 260 | } | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 261 |  | 
|  | 262 | if (wpa_s->beacon_rep_data.token) | 
|  | 263 | wpas_rrm_refuse_request(wpa_s); | 
|  | 264 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 265 | return; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 266 | } | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 267 |  | 
|  | 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 Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 274 | } | 
|  | 275 |  | 
|  | 276 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 277 | /** | 
|  | 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 Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 283 | int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, | 
|  | 284 | struct wpa_driver_scan_params *params) | 
|  | 285 | { | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 286 | struct wpa_driver_scan_params *ctx; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 287 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 288 | if (wpa_s->scan_work) { | 
|  | 289 | wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending"); | 
|  | 290 | return -1; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 291 | } | 
|  | 292 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 293 | ctx = wpa_scan_clone_params(params); | 
| Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 294 | if (!ctx || | 
|  | 295 | radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 296 | { | 
|  | 297 | wpa_scan_free_params(ctx); | 
| Dmitry Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 298 | wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 299 | return -1; | 
|  | 300 | } | 
|  | 301 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 302 | wpa_s->wps_scan_done = false; | 
|  | 303 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 304 | return 0; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 305 | } | 
|  | 306 |  | 
|  | 307 |  | 
|  | 308 | static void | 
|  | 309 | wpa_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 |  | 
|  | 320 | static void | 
|  | 321 | wpa_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 Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 332 | static int | 
|  | 333 | wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, | 
|  | 334 | struct wpa_driver_scan_params *params) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 335 | { | 
|  | 336 | int ret; | 
| Dmitry Shmidt | b7b4d0e | 2013-08-26 12:09:05 -0700 | [diff] [blame] | 337 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 338 | wpa_supplicant_notify_scanning(wpa_s, 1); | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 339 | ret = wpa_drv_sched_scan(wpa_s, params); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 340 | if (ret) | 
|  | 341 | wpa_supplicant_notify_scanning(wpa_s, 0); | 
| Dmitry Shmidt | b96dad4 | 2013-11-05 10:07:29 -0800 | [diff] [blame] | 342 | else | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 343 | wpa_s->sched_scanning = 1; | 
|  | 344 |  | 
|  | 345 | return ret; | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 |  | 
| Dmitry Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 349 | static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 350 | { | 
|  | 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 Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 359 |  | 
|  | 360 | return ret; | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 |  | 
|  | 364 | static struct wpa_driver_scan_filter * | 
|  | 365 | wpa_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 Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 381 | ssids = os_calloc(count, sizeof(struct wpa_driver_scan_filter)); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 382 | 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 Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 397 | #ifdef CONFIG_P2P | 
|  | 398 | static 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 Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 420 | static 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 Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 432 | params->freqs = os_calloc(2, sizeof(int)); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 433 | 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(¶ms->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 Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 446 |  | 
|  | 447 | if (params->freqs == NULL && wpa_s->p2p_in_invitation) { | 
| Sunil Ravi | af8751c | 2023-03-29 11:35:17 -0700 | [diff] [blame] | 448 | struct wpa_ssid *ssid = wpa_s->current_ssid; | 
|  | 449 |  | 
| Dmitry Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 450 | /* | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 451 | * Perform a single-channel scan if the GO has already been | 
|  | 452 | * discovered on another non-P2P interface. Note that a scan | 
| Sunil Ravi | af8751c | 2023-03-29 11:35:17 -0700 | [diff] [blame] | 453 | * initiated by a P2P interface (e.g., the device interface) | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 454 | * should already have sufficient IEs and scan results will be | 
|  | 455 | * fetched on interface creation in that case. | 
|  | 456 | */ | 
| Sunil Ravi | af8751c | 2023-03-29 11:35:17 -0700 | [diff] [blame] | 457 | if (wpa_s->p2p_in_invitation == 1 && ssid) { | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 458 | struct wpa_supplicant *ifs; | 
|  | 459 | struct wpa_bss *bss = NULL; | 
| Sunil Ravi | af8751c | 2023-03-29 11:35:17 -0700 | [diff] [blame] | 460 | const u8 *bssid = ssid->bssid_set ? ssid->bssid : NULL; | 
|  | 461 |  | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 462 | dl_list_for_each(ifs, &wpa_s->radio->ifaces, | 
|  | 463 | struct wpa_supplicant, radio_list) { | 
|  | 464 | bss = wpa_bss_get(ifs, bssid, ssid->ssid, | 
|  | 465 | ssid->ssid_len); | 
|  | 466 | if (bss) | 
|  | 467 | break; | 
|  | 468 | } | 
|  | 469 | if (bss && !disabled_freq(wpa_s, bss->freq)) { | 
|  | 470 | params->freqs = os_calloc(2, sizeof(int)); | 
| Matthew Wang | afc981e | 2023-03-17 21:30:12 +0000 | [diff] [blame] | 471 | if (params->freqs) { | 
|  | 472 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 473 | "P2P: Scan only the known GO frequency %d MHz during invitation", | 
|  | 474 | bss->freq); | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 475 | params->freqs[0] = bss->freq; | 
| Matthew Wang | afc981e | 2023-03-17 21:30:12 +0000 | [diff] [blame] | 476 | } | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 477 | } | 
|  | 478 | } | 
| Sunil Ravi | af8751c | 2023-03-29 11:35:17 -0700 | [diff] [blame] | 479 |  | 
| Matthew Wang | dcf1945 | 2022-11-07 20:42:52 -0800 | [diff] [blame] | 480 | /* | 
| Dmitry Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 481 | * Optimize scan based on GO information during persistent | 
|  | 482 | * group reinvocation | 
|  | 483 | */ | 
| Matthew Wang | afc981e | 2023-03-17 21:30:12 +0000 | [diff] [blame] | 484 | if (!params->freqs && wpa_s->p2p_in_invitation < 5 && | 
| Dmitry Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 485 | wpa_s->p2p_invite_go_freq > 0) { | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 486 | if (wpa_s->p2p_invite_go_freq == 2 || | 
|  | 487 | wpa_s->p2p_invite_go_freq == 5) { | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 488 | enum hostapd_hw_mode mode; | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 489 |  | 
|  | 490 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 491 | "P2P: Scan only GO preferred band %d GHz during invitation", | 
|  | 492 | wpa_s->p2p_invite_go_freq); | 
|  | 493 |  | 
|  | 494 | if (!wpa_s->hw.modes) | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 495 | return; | 
|  | 496 | mode = wpa_s->p2p_invite_go_freq == 5 ? | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 497 | HOSTAPD_MODE_IEEE80211A : | 
|  | 498 | HOSTAPD_MODE_IEEE80211G; | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 499 | if (wpa_s->p2p_in_invitation <= 2) | 
|  | 500 | wpa_add_scan_freqs_list(wpa_s, mode, | 
|  | 501 | params, false, | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 502 | false, true); | 
|  | 503 | if (!params->freqs || params->freqs[0] == 0) | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 504 | wpa_add_scan_freqs_list(wpa_s, mode, | 
|  | 505 | params, false, | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 506 | false, false); | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 507 | } else { | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 508 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 509 | "P2P: Scan only GO preferred frequency %d MHz during invitation", | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 510 | wpa_s->p2p_invite_go_freq); | 
|  | 511 | params->freqs = os_calloc(2, sizeof(int)); | 
|  | 512 | if (params->freqs) | 
|  | 513 | params->freqs[0] = | 
|  | 514 | wpa_s->p2p_invite_go_freq; | 
|  | 515 | } | 
| Dmitry Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 516 | } | 
|  | 517 | wpa_s->p2p_in_invitation++; | 
|  | 518 | if (wpa_s->p2p_in_invitation > 20) { | 
|  | 519 | /* | 
|  | 520 | * This should not really happen since the variable is | 
|  | 521 | * cleared on group removal, but if it does happen, make | 
|  | 522 | * sure we do not get stuck in special invitation scan | 
|  | 523 | * mode. | 
|  | 524 | */ | 
|  | 525 | wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation"); | 
|  | 526 | wpa_s->p2p_in_invitation = 0; | 
| Matthew Wang | 06b4247 | 2022-11-10 06:56:31 +0000 | [diff] [blame] | 527 | wpa_s->p2p_retry_limit = 0; | 
| Dmitry Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 528 | } | 
|  | 529 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 530 | #endif /* CONFIG_P2P */ | 
|  | 531 |  | 
|  | 532 | #ifdef CONFIG_WPS | 
|  | 533 | if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { | 
|  | 534 | /* | 
|  | 535 | * Optimize post-provisioning scan based on channel used | 
|  | 536 | * during provisioning. | 
|  | 537 | */ | 
|  | 538 | wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz " | 
|  | 539 | "that was used during provisioning", wpa_s->wps_freq); | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 540 | params->freqs = os_calloc(2, sizeof(int)); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 541 | if (params->freqs) | 
|  | 542 | params->freqs[0] = wpa_s->wps_freq; | 
|  | 543 | wpa_s->after_wps--; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 544 | } else if (wpa_s->after_wps) | 
|  | 545 | wpa_s->after_wps--; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 546 |  | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 547 | if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq) | 
|  | 548 | { | 
|  | 549 | /* Optimize provisioning scan based on already known channel */ | 
|  | 550 | wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz", | 
|  | 551 | wpa_s->wps_freq); | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 552 | params->freqs = os_calloc(2, sizeof(int)); | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 553 | if (params->freqs) | 
|  | 554 | params->freqs[0] = wpa_s->wps_freq; | 
|  | 555 | wpa_s->known_wps_freq = 0; /* only do this once */ | 
|  | 556 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 557 | #endif /* CONFIG_WPS */ | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 |  | 
|  | 561 | #ifdef CONFIG_INTERWORKING | 
|  | 562 | static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, | 
|  | 563 | struct wpabuf *buf) | 
|  | 564 | { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 565 | wpabuf_put_u8(buf, WLAN_EID_INTERWORKING); | 
|  | 566 | wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 : | 
|  | 567 | 1 + ETH_ALEN); | 
|  | 568 | wpabuf_put_u8(buf, wpa_s->conf->access_network_type); | 
|  | 569 | /* No Venue Info */ | 
|  | 570 | if (!is_zero_ether_addr(wpa_s->conf->hessid)) | 
|  | 571 | wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN); | 
|  | 572 | } | 
|  | 573 | #endif /* CONFIG_INTERWORKING */ | 
|  | 574 |  | 
|  | 575 |  | 
| Hai Shalom | ce48b4a | 2018-09-05 11:41:35 -0700 | [diff] [blame] | 576 | #ifdef CONFIG_MBO | 
|  | 577 | static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s, | 
|  | 578 | struct wpabuf **ie) | 
|  | 579 | { | 
|  | 580 | if (wpabuf_resize(ie, 5)) { | 
|  | 581 | wpa_printf(MSG_DEBUG, | 
|  | 582 | "Failed to allocate space for FILS Request Parameters element"); | 
|  | 583 | return; | 
|  | 584 | } | 
|  | 585 |  | 
|  | 586 | /* FILS Request Parameters element */ | 
|  | 587 | wpabuf_put_u8(*ie, WLAN_EID_EXTENSION); | 
|  | 588 | wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */ | 
|  | 589 | wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS); | 
|  | 590 | /* Parameter control bitmap */ | 
|  | 591 | wpabuf_put_u8(*ie, 0); | 
|  | 592 | /* Max Channel Time field - contains the value of MaxChannelTime | 
|  | 593 | * parameter of the MLME-SCAN.request primitive represented in units of | 
|  | 594 | * TUs, as an unsigned integer. A Max Channel Time field value of 255 | 
|  | 595 | * is used to indicate any duration of more than 254 TUs, or an | 
|  | 596 | * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178) | 
|  | 597 | */ | 
|  | 598 | wpabuf_put_u8(*ie, 255); | 
|  | 599 | } | 
|  | 600 | #endif /* CONFIG_MBO */ | 
|  | 601 |  | 
|  | 602 |  | 
| Dmitry Shmidt | 7f2c753 | 2016-08-15 09:48:12 -0700 | [diff] [blame] | 603 | void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) | 
|  | 604 | { | 
|  | 605 | struct wpabuf *default_ies = NULL; | 
|  | 606 | u8 ext_capab[18]; | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 607 | int ext_capab_len, frame_id; | 
| Dmitry Shmidt | 7f2c753 | 2016-08-15 09:48:12 -0700 | [diff] [blame] | 608 | enum wpa_driver_if_type type = WPA_IF_STATION; | 
|  | 609 |  | 
|  | 610 | #ifdef CONFIG_P2P | 
|  | 611 | if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) | 
|  | 612 | type = WPA_IF_P2P_CLIENT; | 
|  | 613 | #endif /* CONFIG_P2P */ | 
|  | 614 |  | 
|  | 615 | wpa_drv_get_ext_capa(wpa_s, type); | 
|  | 616 |  | 
|  | 617 | ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, | 
|  | 618 | sizeof(ext_capab)); | 
|  | 619 | if (ext_capab_len > 0 && | 
|  | 620 | wpabuf_resize(&default_ies, ext_capab_len) == 0) | 
|  | 621 | wpabuf_put_data(default_ies, ext_capab, ext_capab_len); | 
|  | 622 |  | 
|  | 623 | #ifdef CONFIG_MBO | 
| Hai Shalom | ce48b4a | 2018-09-05 11:41:35 -0700 | [diff] [blame] | 624 | if (wpa_s->enable_oce & OCE_STA) | 
|  | 625 | wpas_fils_req_param_add_max_channel(wpa_s, &default_ies); | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 626 | /* Send MBO and OCE capabilities */ | 
|  | 627 | if (wpabuf_resize(&default_ies, 12) == 0) | 
| Dmitry Shmidt | 7f2c753 | 2016-08-15 09:48:12 -0700 | [diff] [blame] | 628 | wpas_mbo_scan_ie(wpa_s, default_ies); | 
|  | 629 | #endif /* CONFIG_MBO */ | 
|  | 630 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 631 | if (type == WPA_IF_P2P_CLIENT) | 
|  | 632 | frame_id = VENDOR_ELEM_PROBE_REQ_P2P; | 
|  | 633 | else | 
|  | 634 | frame_id = VENDOR_ELEM_PROBE_REQ; | 
|  | 635 |  | 
|  | 636 | if (wpa_s->vendor_elem[frame_id]) { | 
|  | 637 | size_t len; | 
|  | 638 |  | 
|  | 639 | len = wpabuf_len(wpa_s->vendor_elem[frame_id]); | 
|  | 640 | if (len > 0 && wpabuf_resize(&default_ies, len) == 0) | 
|  | 641 | wpabuf_put_buf(default_ies, | 
|  | 642 | wpa_s->vendor_elem[frame_id]); | 
|  | 643 | } | 
|  | 644 |  | 
| Dmitry Shmidt | 7f2c753 | 2016-08-15 09:48:12 -0700 | [diff] [blame] | 645 | if (default_ies) | 
|  | 646 | wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies), | 
|  | 647 | wpabuf_len(default_ies)); | 
|  | 648 | wpabuf_free(default_ies); | 
|  | 649 | } | 
|  | 650 |  | 
|  | 651 |  | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 652 | static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 653 | { | 
|  | 654 | struct wpabuf *extra_ie = NULL; | 
| Dmitry Shmidt | dda10c2 | 2015-03-24 16:05:01 -0700 | [diff] [blame] | 655 | u8 ext_capab[18]; | 
|  | 656 | int ext_capab_len; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 657 | #ifdef CONFIG_WPS | 
|  | 658 | int wps = 0; | 
|  | 659 | enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; | 
|  | 660 | #endif /* CONFIG_WPS */ | 
|  | 661 |  | 
| Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 662 | #ifdef CONFIG_P2P | 
|  | 663 | if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) | 
|  | 664 | wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); | 
|  | 665 | else | 
|  | 666 | #endif /* CONFIG_P2P */ | 
|  | 667 | wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); | 
|  | 668 |  | 
| Dmitry Shmidt | dda10c2 | 2015-03-24 16:05:01 -0700 | [diff] [blame] | 669 | ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, | 
|  | 670 | sizeof(ext_capab)); | 
|  | 671 | if (ext_capab_len > 0 && | 
|  | 672 | wpabuf_resize(&extra_ie, ext_capab_len) == 0) | 
|  | 673 | wpabuf_put_data(extra_ie, ext_capab, ext_capab_len); | 
|  | 674 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 675 | #ifdef CONFIG_INTERWORKING | 
|  | 676 | if (wpa_s->conf->interworking && | 
|  | 677 | wpabuf_resize(&extra_ie, 100) == 0) | 
|  | 678 | wpas_add_interworking_elements(wpa_s, extra_ie); | 
|  | 679 | #endif /* CONFIG_INTERWORKING */ | 
|  | 680 |  | 
| Hai Shalom | ce48b4a | 2018-09-05 11:41:35 -0700 | [diff] [blame] | 681 | #ifdef CONFIG_MBO | 
|  | 682 | if (wpa_s->enable_oce & OCE_STA) | 
|  | 683 | wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie); | 
|  | 684 | #endif /* CONFIG_MBO */ | 
|  | 685 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 686 | #ifdef CONFIG_WPS | 
|  | 687 | wps = wpas_wps_in_use(wpa_s, &req_type); | 
|  | 688 |  | 
|  | 689 | if (wps) { | 
|  | 690 | struct wpabuf *wps_ie; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 691 | wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON : | 
|  | 692 | DEV_PW_DEFAULT, | 
|  | 693 | &wpa_s->wps->dev, | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 694 | wpa_s->wps->uuid, req_type, | 
|  | 695 | 0, NULL); | 
|  | 696 | if (wps_ie) { | 
|  | 697 | if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) | 
|  | 698 | wpabuf_put_buf(extra_ie, wps_ie); | 
|  | 699 | wpabuf_free(wps_ie); | 
|  | 700 | } | 
|  | 701 | } | 
|  | 702 |  | 
|  | 703 | #ifdef CONFIG_P2P | 
|  | 704 | if (wps) { | 
|  | 705 | size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); | 
|  | 706 | if (wpabuf_resize(&extra_ie, ielen) == 0) | 
|  | 707 | wpas_p2p_scan_ie(wpa_s, extra_ie); | 
|  | 708 | } | 
|  | 709 | #endif /* CONFIG_P2P */ | 
|  | 710 |  | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 711 | wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie); | 
|  | 712 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 713 | #endif /* CONFIG_WPS */ | 
|  | 714 |  | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 715 | #ifdef CONFIG_HS20 | 
| Hai Shalom | 74f70d4 | 2019-02-11 14:42:39 -0800 | [diff] [blame] | 716 | if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0) | 
|  | 717 | wpas_hs20_add_indication(extra_ie, -1, 0); | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 718 | #endif /* CONFIG_HS20 */ | 
|  | 719 |  | 
| Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 720 | #ifdef CONFIG_FST | 
|  | 721 | if (wpa_s->fst_ies && | 
|  | 722 | wpabuf_resize(&extra_ie, wpabuf_len(wpa_s->fst_ies)) == 0) | 
|  | 723 | wpabuf_put_buf(extra_ie, wpa_s->fst_ies); | 
|  | 724 | #endif /* CONFIG_FST */ | 
|  | 725 |  | 
| Dmitry Shmidt | 57c2d39 | 2016-02-23 13:40:19 -0800 | [diff] [blame] | 726 | #ifdef CONFIG_MBO | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 727 | /* Send MBO and OCE capabilities */ | 
|  | 728 | if (wpabuf_resize(&extra_ie, 12) == 0) | 
| Dmitry Shmidt | 57c2d39 | 2016-02-23 13:40:19 -0800 | [diff] [blame] | 729 | wpas_mbo_scan_ie(wpa_s, extra_ie); | 
|  | 730 | #endif /* CONFIG_MBO */ | 
|  | 731 |  | 
| Dmitry Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 732 | if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) { | 
|  | 733 | struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]; | 
|  | 734 |  | 
|  | 735 | if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0) | 
|  | 736 | wpabuf_put_buf(extra_ie, buf); | 
|  | 737 | } | 
|  | 738 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 739 | return extra_ie; | 
|  | 740 | } | 
|  | 741 |  | 
|  | 742 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 743 | #ifdef CONFIG_P2P | 
|  | 744 |  | 
|  | 745 | /* | 
|  | 746 | * Check whether there are any enabled networks or credentials that could be | 
|  | 747 | * used for a non-P2P connection. | 
|  | 748 | */ | 
|  | 749 | static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) | 
|  | 750 | { | 
|  | 751 | struct wpa_ssid *ssid; | 
|  | 752 |  | 
|  | 753 | for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
|  | 754 | if (wpas_network_disabled(wpa_s, ssid)) | 
|  | 755 | continue; | 
|  | 756 | if (!ssid->p2p_group) | 
|  | 757 | return 1; | 
|  | 758 | } | 
|  | 759 |  | 
|  | 760 | if (wpa_s->conf->cred && wpa_s->conf->interworking && | 
|  | 761 | wpa_s->conf->auto_interworking) | 
|  | 762 | return 1; | 
|  | 763 |  | 
|  | 764 | return 0; | 
|  | 765 | } | 
|  | 766 |  | 
| Dmitry Shmidt | ea69e84 | 2013-05-13 14:52:28 -0700 | [diff] [blame] | 767 | #endif /* CONFIG_P2P */ | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 768 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 769 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 770 | int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s, | 
|  | 771 | enum hostapd_hw_mode band, | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 772 | struct wpa_driver_scan_params *params, | 
|  | 773 | bool is_6ghz, bool only_6ghz_psc, | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 774 | bool exclude_radar) | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 775 | { | 
|  | 776 | /* Include only supported channels for the specified band */ | 
|  | 777 | struct hostapd_hw_modes *mode; | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 778 | int num_chans = 0; | 
|  | 779 | int *freqs, i; | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 780 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 781 | mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz); | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 782 | if (!mode || !mode->num_channels) | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 783 | return -1; | 
|  | 784 |  | 
|  | 785 | if (params->freqs) { | 
|  | 786 | while (params->freqs[num_chans]) | 
|  | 787 | num_chans++; | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 788 | } | 
|  | 789 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 790 | freqs = os_realloc(params->freqs, | 
|  | 791 | (num_chans + mode->num_channels + 1) * sizeof(int)); | 
|  | 792 | if (!freqs) | 
|  | 793 | return -1; | 
|  | 794 |  | 
|  | 795 | params->freqs = freqs; | 
|  | 796 | for (i = 0; i < mode->num_channels; i++) { | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 797 | if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) | 
|  | 798 | continue; | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 799 | if (exclude_radar && | 
|  | 800 | (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)) | 
| Matthew Wang | 3617311 | 2022-11-07 21:48:44 -0800 | [diff] [blame] | 801 | continue; | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 802 |  | 
|  | 803 | if (is_6ghz && only_6ghz_psc && | 
|  | 804 | !is_6ghz_psc_frequency(mode->channels[i].freq)) | 
|  | 805 | continue; | 
|  | 806 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 807 | params->freqs[num_chans++] = mode->channels[i].freq; | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 808 | } | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 809 | params->freqs[num_chans] = 0; | 
|  | 810 |  | 
|  | 811 | return 0; | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 812 | } | 
|  | 813 |  | 
|  | 814 |  | 
|  | 815 | static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, | 
|  | 816 | struct wpa_driver_scan_params *params) | 
|  | 817 | { | 
|  | 818 | if (wpa_s->hw.modes == NULL) | 
|  | 819 | return; /* unknown what channels the driver supports */ | 
|  | 820 | if (params->freqs) | 
|  | 821 | return; /* already using a limited channel set */ | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 822 |  | 
|  | 823 | if (wpa_s->setband_mask & WPA_SETBAND_5G) | 
|  | 824 | wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 825 | false, false, false); | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 826 | if (wpa_s->setband_mask & WPA_SETBAND_2G) | 
|  | 827 | wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params, | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 828 | false, false, false); | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 829 | if (wpa_s->setband_mask & WPA_SETBAND_6G) | 
|  | 830 | wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 831 | true, false, false); | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 832 | } | 
|  | 833 |  | 
|  | 834 |  | 
| Hai Shalom | 39ba6fc | 2019-01-22 12:40:38 -0800 | [diff] [blame] | 835 | static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s, | 
|  | 836 | struct wpa_driver_scan_params *params, | 
|  | 837 | size_t max_ssids, const u8 *ssid, size_t ssid_len) | 
|  | 838 | { | 
|  | 839 | unsigned int j; | 
|  | 840 |  | 
|  | 841 | for (j = 0; j < params->num_ssids; j++) { | 
|  | 842 | if (params->ssids[j].ssid_len == ssid_len && | 
|  | 843 | params->ssids[j].ssid && | 
|  | 844 | os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0) | 
|  | 845 | return; /* already in the list */ | 
|  | 846 | } | 
|  | 847 |  | 
|  | 848 | if (params->num_ssids + 1 > max_ssids) { | 
|  | 849 | wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request"); | 
|  | 850 | return; | 
|  | 851 | } | 
|  | 852 |  | 
|  | 853 | wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s", | 
|  | 854 | wpa_ssid_txt(ssid, ssid_len)); | 
|  | 855 |  | 
|  | 856 | params->ssids[params->num_ssids].ssid = ssid; | 
|  | 857 | params->ssids[params->num_ssids].ssid_len = ssid_len; | 
|  | 858 | params->num_ssids++; | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 |  | 
|  | 862 | static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s, | 
|  | 863 | struct wpa_driver_scan_params *params, | 
|  | 864 | struct wpa_ssid *ssid, size_t max_ssids) | 
|  | 865 | { | 
|  | 866 | #ifdef CONFIG_OWE | 
|  | 867 | struct wpa_bss *bss; | 
|  | 868 |  | 
|  | 869 | if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE)) | 
|  | 870 | return; | 
|  | 871 |  | 
|  | 872 | wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s", | 
|  | 873 | wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
|  | 874 |  | 
|  | 875 | dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { | 
|  | 876 | const u8 *owe, *pos, *end; | 
|  | 877 | const u8 *owe_ssid; | 
|  | 878 | size_t owe_ssid_len; | 
|  | 879 |  | 
|  | 880 | if (bss->ssid_len != ssid->ssid_len || | 
|  | 881 | os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0) | 
|  | 882 | continue; | 
|  | 883 |  | 
|  | 884 | owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); | 
|  | 885 | if (!owe || owe[1] < 4) | 
|  | 886 | continue; | 
|  | 887 |  | 
|  | 888 | pos = owe + 6; | 
|  | 889 | end = owe + 2 + owe[1]; | 
|  | 890 |  | 
|  | 891 | /* Must include BSSID and ssid_len */ | 
|  | 892 | if (end - pos < ETH_ALEN + 1) | 
|  | 893 | return; | 
|  | 894 |  | 
|  | 895 | /* Skip BSSID */ | 
|  | 896 | pos += ETH_ALEN; | 
|  | 897 | owe_ssid_len = *pos++; | 
|  | 898 | owe_ssid = pos; | 
|  | 899 |  | 
|  | 900 | if ((size_t) (end - pos) < owe_ssid_len || | 
|  | 901 | owe_ssid_len > SSID_MAX_LEN) | 
|  | 902 | return; | 
|  | 903 |  | 
|  | 904 | wpa_printf(MSG_DEBUG, | 
|  | 905 | "OWE: scan_ssids: transition mode OWE ssid=%s", | 
|  | 906 | wpa_ssid_txt(owe_ssid, owe_ssid_len)); | 
|  | 907 |  | 
|  | 908 | wpa_add_scan_ssid(wpa_s, params, max_ssids, | 
|  | 909 | owe_ssid, owe_ssid_len); | 
|  | 910 | return; | 
|  | 911 | } | 
|  | 912 | #endif /* CONFIG_OWE */ | 
|  | 913 | } | 
|  | 914 |  | 
|  | 915 |  | 
| Dmitry Shmidt | c281702 | 2014-07-02 10:32:10 -0700 | [diff] [blame] | 916 | static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, | 
|  | 917 | struct wpa_driver_scan_params *params, | 
|  | 918 | size_t max_ssids) | 
|  | 919 | { | 
|  | 920 | unsigned int i; | 
|  | 921 | struct wpa_ssid *ssid; | 
|  | 922 |  | 
| Dmitry Shmidt | 58d12ad | 2016-07-28 10:07:03 -0700 | [diff] [blame] | 923 | /* | 
|  | 924 | * For devices with max_ssids greater than 1, leave the last slot empty | 
|  | 925 | * for adding the wildcard scan entry. | 
|  | 926 | */ | 
|  | 927 | max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids; | 
|  | 928 |  | 
| Dmitry Shmidt | c281702 | 2014-07-02 10:32:10 -0700 | [diff] [blame] | 929 | for (i = 0; i < wpa_s->scan_id_count; i++) { | 
| Dmitry Shmidt | c281702 | 2014-07-02 10:32:10 -0700 | [diff] [blame] | 930 | ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]); | 
| Hai Shalom | 39ba6fc | 2019-01-22 12:40:38 -0800 | [diff] [blame] | 931 | if (!ssid) | 
| Dmitry Shmidt | c281702 | 2014-07-02 10:32:10 -0700 | [diff] [blame] | 932 | continue; | 
| Hai Shalom | 39ba6fc | 2019-01-22 12:40:38 -0800 | [diff] [blame] | 933 | if (ssid->scan_ssid) | 
|  | 934 | wpa_add_scan_ssid(wpa_s, params, max_ssids, | 
|  | 935 | ssid->ssid, ssid->ssid_len); | 
|  | 936 | /* | 
|  | 937 | * Also add the SSID of the OWE BSS, to allow discovery of | 
|  | 938 | * transition mode APs more quickly. | 
|  | 939 | */ | 
|  | 940 | wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids); | 
| Dmitry Shmidt | c281702 | 2014-07-02 10:32:10 -0700 | [diff] [blame] | 941 | } | 
|  | 942 |  | 
|  | 943 | wpa_s->scan_id_count = 0; | 
|  | 944 | } | 
|  | 945 |  | 
|  | 946 |  | 
| Dmitry Shmidt | 7a53dbb | 2015-06-11 13:13:53 -0700 | [diff] [blame] | 947 | static int wpa_set_ssids_from_scan_req(struct wpa_supplicant *wpa_s, | 
|  | 948 | struct wpa_driver_scan_params *params, | 
|  | 949 | size_t max_ssids) | 
|  | 950 | { | 
|  | 951 | unsigned int i; | 
|  | 952 |  | 
|  | 953 | if (wpa_s->ssids_from_scan_req == NULL || | 
|  | 954 | wpa_s->num_ssids_from_scan_req == 0) | 
|  | 955 | return 0; | 
|  | 956 |  | 
|  | 957 | if (wpa_s->num_ssids_from_scan_req > max_ssids) { | 
|  | 958 | wpa_s->num_ssids_from_scan_req = max_ssids; | 
|  | 959 | wpa_printf(MSG_DEBUG, "Over max scan SSIDs from scan req: %u", | 
|  | 960 | (unsigned int) max_ssids); | 
|  | 961 | } | 
|  | 962 |  | 
|  | 963 | for (i = 0; i < wpa_s->num_ssids_from_scan_req; i++) { | 
|  | 964 | params->ssids[i].ssid = wpa_s->ssids_from_scan_req[i].ssid; | 
|  | 965 | params->ssids[i].ssid_len = | 
|  | 966 | wpa_s->ssids_from_scan_req[i].ssid_len; | 
|  | 967 | wpa_hexdump_ascii(MSG_DEBUG, "specific SSID", | 
|  | 968 | params->ssids[i].ssid, | 
|  | 969 | params->ssids[i].ssid_len); | 
|  | 970 | } | 
|  | 971 |  | 
|  | 972 | params->num_ssids = wpa_s->num_ssids_from_scan_req; | 
|  | 973 | wpa_s->num_ssids_from_scan_req = 0; | 
|  | 974 | return 1; | 
|  | 975 | } | 
|  | 976 |  | 
|  | 977 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 978 | static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) | 
|  | 979 | { | 
|  | 980 | struct wpa_supplicant *wpa_s = eloop_ctx; | 
|  | 981 | struct wpa_ssid *ssid; | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 982 | int ret, p2p_in_prog; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 983 | struct wpabuf *extra_ie = NULL; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 984 | struct wpa_driver_scan_params params; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 985 | struct wpa_driver_scan_params *scan_params; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 986 | size_t max_ssids; | 
| Dmitry Shmidt | 203eadb | 2015-03-05 14:16:04 -0800 | [diff] [blame] | 987 | int connect_without_scan = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 988 |  | 
| Dmitry Shmidt | 2933359 | 2017-01-09 12:27:11 -0800 | [diff] [blame] | 989 | wpa_s->ignore_post_flush_scan_res = 0; | 
|  | 990 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 991 | if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { | 
|  | 992 | wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); | 
|  | 993 | return; | 
|  | 994 | } | 
|  | 995 |  | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 996 | if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) { | 
| Dmitry Shmidt | aa53251 | 2012-09-24 10:35:31 -0700 | [diff] [blame] | 997 | wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 998 | wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); | 
|  | 999 | return; | 
|  | 1000 | } | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 1001 |  | 
| Dmitry Shmidt | 5887a9d | 2012-09-14 10:47:43 -0700 | [diff] [blame] | 1002 | if (wpa_s->scanning) { | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 1003 | /* | 
|  | 1004 | * If we are already in scanning state, we shall reschedule the | 
|  | 1005 | * the incoming scan request. | 
|  | 1006 | */ | 
|  | 1007 | wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req"); | 
|  | 1008 | wpa_supplicant_req_scan(wpa_s, 1, 0); | 
| Dmitry Shmidt | 5887a9d | 2012-09-14 10:47:43 -0700 | [diff] [blame] | 1009 | return; | 
|  | 1010 | } | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 1011 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1012 | if (!wpa_supplicant_enabled_networks(wpa_s) && | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1013 | wpa_s->scan_req == NORMAL_SCAN_REQ) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1014 | wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); | 
|  | 1015 | wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); | 
|  | 1016 | return; | 
|  | 1017 | } | 
|  | 1018 |  | 
|  | 1019 | if (wpa_s->conf->ap_scan != 0 && | 
|  | 1020 | (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { | 
|  | 1021 | wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " | 
|  | 1022 | "overriding ap_scan configuration"); | 
|  | 1023 | wpa_s->conf->ap_scan = 0; | 
|  | 1024 | wpas_notify_ap_scan_changed(wpa_s); | 
|  | 1025 | } | 
|  | 1026 |  | 
|  | 1027 | if (wpa_s->conf->ap_scan == 0) { | 
|  | 1028 | wpa_supplicant_gen_assoc_event(wpa_s); | 
|  | 1029 | return; | 
|  | 1030 | } | 
|  | 1031 |  | 
| Dmitry Shmidt | 203eadb | 2015-03-05 14:16:04 -0800 | [diff] [blame] | 1032 | ssid = NULL; | 
|  | 1033 | if (wpa_s->scan_req != MANUAL_SCAN_REQ && | 
|  | 1034 | wpa_s->connect_without_scan) { | 
|  | 1035 | connect_without_scan = 1; | 
|  | 1036 | for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
|  | 1037 | if (ssid == wpa_s->connect_without_scan) | 
|  | 1038 | break; | 
|  | 1039 | } | 
|  | 1040 | } | 
|  | 1041 |  | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 1042 | p2p_in_prog = wpas_p2p_in_progress(wpa_s); | 
| Dmitry Shmidt | 203eadb | 2015-03-05 14:16:04 -0800 | [diff] [blame] | 1043 | if (p2p_in_prog && p2p_in_prog != 2 && | 
|  | 1044 | (!ssid || | 
|  | 1045 | (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) { | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1046 | wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress"); | 
|  | 1047 | wpa_supplicant_req_scan(wpa_s, 5, 0); | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 1048 | return; | 
|  | 1049 | } | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 1050 |  | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 1051 | /* | 
|  | 1052 | * Don't cancel the scan based on ongoing PNO; defer it. Some scans are | 
|  | 1053 | * used for changing modes inside wpa_supplicant (roaming, | 
|  | 1054 | * auto-reconnect, etc). Discarding the scan might hurt these processes. | 
|  | 1055 | * The normal use case for PNO is to suspend the host immediately after | 
|  | 1056 | * starting PNO, so the periodic 100 ms attempts to run the scan do not | 
|  | 1057 | * normally happen in practice multiple times, i.e., this is simply | 
|  | 1058 | * restarting scanning once the host is woken up and PNO stopped. | 
|  | 1059 | */ | 
|  | 1060 | if (wpa_s->pno || wpa_s->pno_sched_pending) { | 
|  | 1061 | wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress"); | 
|  | 1062 | wpa_supplicant_req_scan(wpa_s, 0, 100000); | 
|  | 1063 | return; | 
|  | 1064 | } | 
|  | 1065 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1066 | if (wpa_s->conf->ap_scan == 2) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1067 | max_ssids = 1; | 
|  | 1068 | else { | 
|  | 1069 | max_ssids = wpa_s->max_scan_ssids; | 
|  | 1070 | if (max_ssids > WPAS_MAX_SCAN_SSIDS) | 
|  | 1071 | max_ssids = WPAS_MAX_SCAN_SSIDS; | 
|  | 1072 | } | 
|  | 1073 |  | 
| Dmitry Shmidt | 01904cf | 2013-12-05 11:08:35 -0800 | [diff] [blame] | 1074 | wpa_s->last_scan_req = wpa_s->scan_req; | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1075 | wpa_s->scan_req = NORMAL_SCAN_REQ; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1076 |  | 
| Dmitry Shmidt | 203eadb | 2015-03-05 14:16:04 -0800 | [diff] [blame] | 1077 | if (connect_without_scan) { | 
|  | 1078 | wpa_s->connect_without_scan = NULL; | 
|  | 1079 | if (ssid) { | 
|  | 1080 | wpa_printf(MSG_DEBUG, "Start a pre-selected network " | 
|  | 1081 | "without scan step"); | 
|  | 1082 | wpa_supplicant_associate(wpa_s, NULL, ssid); | 
|  | 1083 | return; | 
|  | 1084 | } | 
|  | 1085 | } | 
|  | 1086 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1087 | os_memset(¶ms, 0, sizeof(params)); | 
|  | 1088 |  | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 1089 | wpa_s->scan_prev_wpa_state = wpa_s->wpa_state; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1090 | if (wpa_s->wpa_state == WPA_DISCONNECTED || | 
|  | 1091 | wpa_s->wpa_state == WPA_INACTIVE) | 
|  | 1092 | wpa_supplicant_set_state(wpa_s, WPA_SCANNING); | 
|  | 1093 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1094 | /* | 
|  | 1095 | * If autoscan has set its own scanning parameters | 
|  | 1096 | */ | 
|  | 1097 | if (wpa_s->autoscan_params != NULL) { | 
|  | 1098 | scan_params = wpa_s->autoscan_params; | 
|  | 1099 | goto scan; | 
|  | 1100 | } | 
|  | 1101 |  | 
| Dmitry Shmidt | 7a53dbb | 2015-06-11 13:13:53 -0700 | [diff] [blame] | 1102 | if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && | 
|  | 1103 | wpa_set_ssids_from_scan_req(wpa_s, ¶ms, max_ssids)) { | 
|  | 1104 | wpa_printf(MSG_DEBUG, "Use specific SSIDs from SCAN command"); | 
|  | 1105 | goto ssid_list_set; | 
|  | 1106 | } | 
|  | 1107 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1108 | #ifdef CONFIG_P2P | 
|  | 1109 | if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) && | 
| Dmitry Shmidt | 807291d | 2015-01-27 13:40:23 -0800 | [diff] [blame] | 1110 | wpa_s->go_params && !wpa_s->conf->passive_scan) { | 
| Dmitry Shmidt | cce0666 | 2013-11-04 18:44:24 -0800 | [diff] [blame] | 1111 | wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)", | 
|  | 1112 | wpa_s->p2p_in_provisioning, | 
|  | 1113 | wpa_s->show_group_started); | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1114 | params.ssids[0].ssid = wpa_s->go_params->ssid; | 
|  | 1115 | params.ssids[0].ssid_len = wpa_s->go_params->ssid_len; | 
|  | 1116 | params.num_ssids = 1; | 
|  | 1117 | goto ssid_list_set; | 
|  | 1118 | } | 
| Dmitry Shmidt | 1590709 | 2014-03-25 10:42:57 -0700 | [diff] [blame] | 1119 |  | 
|  | 1120 | if (wpa_s->p2p_in_invitation) { | 
|  | 1121 | if (wpa_s->current_ssid) { | 
|  | 1122 | wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation"); | 
|  | 1123 | params.ssids[0].ssid = wpa_s->current_ssid->ssid; | 
|  | 1124 | params.ssids[0].ssid_len = | 
|  | 1125 | wpa_s->current_ssid->ssid_len; | 
|  | 1126 | params.num_ssids = 1; | 
|  | 1127 | } else { | 
|  | 1128 | wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation"); | 
|  | 1129 | } | 
|  | 1130 | goto ssid_list_set; | 
|  | 1131 | } | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1132 | #endif /* CONFIG_P2P */ | 
|  | 1133 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1134 | /* Find the starting point from which to continue scanning */ | 
|  | 1135 | ssid = wpa_s->conf->ssid; | 
|  | 1136 | if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { | 
|  | 1137 | while (ssid) { | 
|  | 1138 | if (ssid == wpa_s->prev_scan_ssid) { | 
|  | 1139 | ssid = ssid->next; | 
|  | 1140 | break; | 
|  | 1141 | } | 
|  | 1142 | ssid = ssid->next; | 
|  | 1143 | } | 
|  | 1144 | } | 
|  | 1145 |  | 
| Dmitry Shmidt | 01904cf | 2013-12-05 11:08:35 -0800 | [diff] [blame] | 1146 | if (wpa_s->last_scan_req != MANUAL_SCAN_REQ && | 
| Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 1147 | #ifdef CONFIG_AP | 
|  | 1148 | !wpa_s->ap_iface && | 
|  | 1149 | #endif /* CONFIG_AP */ | 
| Dmitry Shmidt | 01904cf | 2013-12-05 11:08:35 -0800 | [diff] [blame] | 1150 | wpa_s->conf->ap_scan == 2) { | 
| Jouni Malinen | 75ecf52 | 2011-06-27 15:19:46 -0700 | [diff] [blame] | 1151 | wpa_s->connect_without_scan = NULL; | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 1152 | wpa_s->prev_scan_wildcard = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1153 | wpa_supplicant_assoc_try(wpa_s, ssid); | 
|  | 1154 | return; | 
|  | 1155 | } else if (wpa_s->conf->ap_scan == 2) { | 
|  | 1156 | /* | 
|  | 1157 | * User-initiated scan request in ap_scan == 2; scan with | 
|  | 1158 | * wildcard SSID. | 
|  | 1159 | */ | 
|  | 1160 | ssid = NULL; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 1161 | } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) { | 
|  | 1162 | /* | 
|  | 1163 | * Perform single-channel single-SSID scan for | 
|  | 1164 | * reassociate-to-same-BSS operation. | 
|  | 1165 | */ | 
|  | 1166 | /* Setup SSID */ | 
|  | 1167 | ssid = wpa_s->current_ssid; | 
|  | 1168 | wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", | 
|  | 1169 | ssid->ssid, ssid->ssid_len); | 
|  | 1170 | params.ssids[0].ssid = ssid->ssid; | 
|  | 1171 | params.ssids[0].ssid_len = ssid->ssid_len; | 
|  | 1172 | params.num_ssids = 1; | 
|  | 1173 |  | 
|  | 1174 | /* | 
|  | 1175 | * Allocate memory for frequency array, allocate one extra | 
|  | 1176 | * slot for the zero-terminator. | 
|  | 1177 | */ | 
|  | 1178 | params.freqs = os_malloc(sizeof(int) * 2); | 
| Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 1179 | if (params.freqs) { | 
|  | 1180 | params.freqs[0] = wpa_s->assoc_freq; | 
|  | 1181 | params.freqs[1] = 0; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 1182 | } | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 1183 |  | 
|  | 1184 | /* | 
|  | 1185 | * Reset the reattach flag so that we fall back to full scan if | 
|  | 1186 | * this scan fails. | 
|  | 1187 | */ | 
|  | 1188 | wpa_s->reattach = 0; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1189 | } else { | 
|  | 1190 | struct wpa_ssid *start = ssid, *tssid; | 
|  | 1191 | int freqs_set = 0; | 
|  | 1192 | if (ssid == NULL && max_ssids > 1) | 
|  | 1193 | ssid = wpa_s->conf->ssid; | 
|  | 1194 | while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1195 | if (!wpas_network_disabled(wpa_s, ssid) && | 
|  | 1196 | ssid->scan_ssid) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1197 | wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", | 
|  | 1198 | ssid->ssid, ssid->ssid_len); | 
|  | 1199 | params.ssids[params.num_ssids].ssid = | 
|  | 1200 | ssid->ssid; | 
|  | 1201 | params.ssids[params.num_ssids].ssid_len = | 
|  | 1202 | ssid->ssid_len; | 
|  | 1203 | params.num_ssids++; | 
|  | 1204 | if (params.num_ssids + 1 >= max_ssids) | 
|  | 1205 | break; | 
|  | 1206 | } | 
| Hai Shalom | 39ba6fc | 2019-01-22 12:40:38 -0800 | [diff] [blame] | 1207 |  | 
|  | 1208 | if (!wpas_network_disabled(wpa_s, ssid)) { | 
|  | 1209 | /* | 
|  | 1210 | * Also add the SSID of the OWE BSS, to allow | 
|  | 1211 | * discovery of transition mode APs more | 
|  | 1212 | * quickly. | 
|  | 1213 | */ | 
|  | 1214 | wpa_add_owe_scan_ssid(wpa_s, ¶ms, ssid, | 
|  | 1215 | max_ssids); | 
|  | 1216 | } | 
|  | 1217 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1218 | ssid = ssid->next; | 
|  | 1219 | if (ssid == start) | 
|  | 1220 | break; | 
|  | 1221 | if (ssid == NULL && max_ssids > 1 && | 
|  | 1222 | start != wpa_s->conf->ssid) | 
|  | 1223 | ssid = wpa_s->conf->ssid; | 
|  | 1224 | } | 
|  | 1225 |  | 
| Dmitry Shmidt | c281702 | 2014-07-02 10:32:10 -0700 | [diff] [blame] | 1226 | if (wpa_s->scan_id_count && | 
|  | 1227 | wpa_s->last_scan_req == MANUAL_SCAN_REQ) | 
|  | 1228 | wpa_set_scan_ssids(wpa_s, ¶ms, max_ssids); | 
|  | 1229 |  | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 1230 | for (tssid = wpa_s->conf->ssid; | 
|  | 1231 | wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid; | 
|  | 1232 | tssid = tssid->next) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1233 | if (wpas_network_disabled(wpa_s, tssid)) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1234 | continue; | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 1235 | if (((params.freqs || !freqs_set) && | 
|  | 1236 | tssid->scan_freq) && | 
|  | 1237 | int_array_len(params.freqs) < 100) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1238 | int_array_concat(¶ms.freqs, | 
|  | 1239 | tssid->scan_freq); | 
|  | 1240 | } else { | 
|  | 1241 | os_free(params.freqs); | 
|  | 1242 | params.freqs = NULL; | 
|  | 1243 | } | 
|  | 1244 | freqs_set = 1; | 
|  | 1245 | } | 
|  | 1246 | int_array_sort_unique(params.freqs); | 
|  | 1247 | } | 
|  | 1248 |  | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 1249 | if (ssid && max_ssids == 1) { | 
|  | 1250 | /* | 
|  | 1251 | * If the driver is limited to 1 SSID at a time interleave | 
|  | 1252 | * wildcard SSID scans with specific SSID scans to avoid | 
|  | 1253 | * waiting a long time for a wildcard scan. | 
|  | 1254 | */ | 
|  | 1255 | if (!wpa_s->prev_scan_wildcard) { | 
|  | 1256 | params.ssids[0].ssid = NULL; | 
|  | 1257 | params.ssids[0].ssid_len = 0; | 
|  | 1258 | wpa_s->prev_scan_wildcard = 1; | 
|  | 1259 | wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for " | 
|  | 1260 | "wildcard SSID (Interleave with specific)"); | 
|  | 1261 | } else { | 
|  | 1262 | wpa_s->prev_scan_ssid = ssid; | 
|  | 1263 | wpa_s->prev_scan_wildcard = 0; | 
|  | 1264 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1265 | "Starting AP scan for specific SSID: %s", | 
|  | 1266 | wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1267 | } | 
| Dmitry Shmidt | c5ec7f5 | 2012-03-06 16:33:24 -0800 | [diff] [blame] | 1268 | } else if (ssid) { | 
|  | 1269 | /* max_ssids > 1 */ | 
|  | 1270 |  | 
|  | 1271 | wpa_s->prev_scan_ssid = ssid; | 
|  | 1272 | wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " | 
|  | 1273 | "the scan request"); | 
|  | 1274 | params.num_ssids++; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1275 | } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && | 
|  | 1276 | wpa_s->manual_scan_passive && params.num_ssids == 0) { | 
|  | 1277 | wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request"); | 
| Dmitry Shmidt | 807291d | 2015-01-27 13:40:23 -0800 | [diff] [blame] | 1278 | } else if (wpa_s->conf->passive_scan) { | 
|  | 1279 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1280 | "Use passive scan based on configuration"); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1281 | } else { | 
|  | 1282 | wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; | 
|  | 1283 | params.num_ssids++; | 
|  | 1284 | wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " | 
|  | 1285 | "SSID"); | 
|  | 1286 | } | 
|  | 1287 |  | 
| Dmitry Shmidt | 7a53dbb | 2015-06-11 13:13:53 -0700 | [diff] [blame] | 1288 | ssid_list_set: | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1289 | wpa_supplicant_optimize_freqs(wpa_s, ¶ms); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1290 | extra_ie = wpa_supplicant_extra_ies(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1291 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1292 | if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 1293 | wpa_s->manual_scan_only_new) { | 
|  | 1294 | wpa_printf(MSG_DEBUG, | 
|  | 1295 | "Request driver to clear scan cache due to manual only_new=1 scan"); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1296 | params.only_new_results = 1; | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 1297 | } | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1298 |  | 
|  | 1299 | if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && | 
|  | 1300 | wpa_s->manual_scan_freqs) { | 
|  | 1301 | wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); | 
|  | 1302 | params.freqs = wpa_s->manual_scan_freqs; | 
|  | 1303 | wpa_s->manual_scan_freqs = NULL; | 
|  | 1304 | } | 
|  | 1305 |  | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 1306 | if (params.freqs == NULL && wpa_s->select_network_scan_freqs) { | 
|  | 1307 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1308 | "Limit select_network scan to specified channels"); | 
|  | 1309 | params.freqs = wpa_s->select_network_scan_freqs; | 
|  | 1310 | wpa_s->select_network_scan_freqs = NULL; | 
|  | 1311 | } | 
|  | 1312 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1313 | if (params.freqs == NULL && wpa_s->next_scan_freqs) { | 
|  | 1314 | wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " | 
|  | 1315 | "generated frequency list"); | 
|  | 1316 | params.freqs = wpa_s->next_scan_freqs; | 
|  | 1317 | } else | 
|  | 1318 | os_free(wpa_s->next_scan_freqs); | 
|  | 1319 | wpa_s->next_scan_freqs = NULL; | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 1320 | wpa_setband_scan_freqs(wpa_s, ¶ms); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1321 |  | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 1322 | /* See if user specified frequencies. If so, scan only those. */ | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 1323 | if (wpa_s->last_scan_req == INITIAL_SCAN_REQ && | 
|  | 1324 | wpa_s->conf->initial_freq_list && !params.freqs) { | 
|  | 1325 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1326 | "Optimize scan based on conf->initial_freq_list"); | 
|  | 1327 | int_array_concat(¶ms.freqs, wpa_s->conf->initial_freq_list); | 
|  | 1328 | } else if (wpa_s->conf->freq_list && !params.freqs) { | 
| Dmitry Shmidt | 51b6ea8 | 2013-05-08 10:42:09 -0700 | [diff] [blame] | 1329 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1330 | "Optimize scan based on conf->freq_list"); | 
|  | 1331 | int_array_concat(¶ms.freqs, wpa_s->conf->freq_list); | 
|  | 1332 | } | 
|  | 1333 |  | 
| Dmitry Shmidt | ea69e84 | 2013-05-13 14:52:28 -0700 | [diff] [blame] | 1334 | /* Use current associated channel? */ | 
|  | 1335 | if (wpa_s->conf->scan_cur_freq && !params.freqs) { | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 1336 | unsigned int num = wpa_s->num_multichan_concurrent; | 
|  | 1337 |  | 
|  | 1338 | params.freqs = os_calloc(num + 1, sizeof(int)); | 
|  | 1339 | if (params.freqs) { | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 1340 | num = get_shared_radio_freqs(wpa_s, params.freqs, num, | 
|  | 1341 | false); | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 1342 | if (num > 0) { | 
|  | 1343 | wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the " | 
|  | 1344 | "current operating channels since " | 
|  | 1345 | "scan_cur_freq is enabled"); | 
|  | 1346 | } else { | 
|  | 1347 | os_free(params.freqs); | 
|  | 1348 | params.freqs = NULL; | 
|  | 1349 | } | 
| Dmitry Shmidt | ea69e84 | 2013-05-13 14:52:28 -0700 | [diff] [blame] | 1350 | } | 
|  | 1351 | } | 
|  | 1352 |  | 
| Hai Shalom | ce48b4a | 2018-09-05 11:41:35 -0700 | [diff] [blame] | 1353 | #ifdef CONFIG_MBO | 
|  | 1354 | if (wpa_s->enable_oce & OCE_STA) | 
|  | 1355 | params.oce_scan = 1; | 
|  | 1356 | #endif /* CONFIG_MBO */ | 
|  | 1357 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1358 | params.filter_ssids = wpa_supplicant_build_filter_ssids( | 
|  | 1359 | wpa_s->conf, ¶ms.num_filter_ssids); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1360 | if (extra_ie) { | 
|  | 1361 | params.extra_ies = wpabuf_head(extra_ie); | 
|  | 1362 | params.extra_ies_len = wpabuf_len(extra_ie); | 
|  | 1363 | } | 
|  | 1364 |  | 
|  | 1365 | #ifdef CONFIG_P2P | 
| Dmitry Shmidt | 413dde7 | 2014-04-11 10:23:22 -0700 | [diff] [blame] | 1366 | if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation || | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1367 | (wpa_s->show_group_started && wpa_s->go_params)) { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1368 | /* | 
|  | 1369 | * The interface may not yet be in P2P mode, so we have to | 
|  | 1370 | * explicitly request P2P probe to disable CCK rates. | 
|  | 1371 | */ | 
|  | 1372 | params.p2p_probe = 1; | 
|  | 1373 | } | 
|  | 1374 | #endif /* CONFIG_P2P */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1375 |  | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 1376 | if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) && | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 1377 | wpa_s->wpa_state <= WPA_SCANNING) | 
|  | 1378 | wpa_setup_mac_addr_rand_params(¶ms, wpa_s->mac_addr_scan); | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 1379 |  | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 1380 | if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) { | 
|  | 1381 | struct wpa_bss *bss; | 
|  | 1382 |  | 
|  | 1383 | params.bssid = wpa_s->next_scan_bssid; | 
|  | 1384 | bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid); | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 1385 | if (!wpa_s->next_scan_bssid_wildcard_ssid && | 
|  | 1386 | bss && bss->ssid_len && params.num_ssids == 1 && | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 1387 | params.ssids[0].ssid_len == 0) { | 
|  | 1388 | params.ssids[0].ssid = bss->ssid; | 
|  | 1389 | params.ssids[0].ssid_len = bss->ssid_len; | 
|  | 1390 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1391 | "Scan a previously specified BSSID " MACSTR | 
|  | 1392 | " and SSID %s", | 
|  | 1393 | MAC2STR(params.bssid), | 
|  | 1394 | wpa_ssid_txt(bss->ssid, bss->ssid_len)); | 
|  | 1395 | } else { | 
|  | 1396 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1397 | "Scan a previously specified BSSID " MACSTR, | 
|  | 1398 | MAC2STR(params.bssid)); | 
|  | 1399 | } | 
|  | 1400 | } | 
|  | 1401 |  | 
| Sunil | 8cd6f4d | 2022-06-28 18:40:46 +0000 | [diff] [blame] | 1402 | if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && | 
|  | 1403 | wpa_s->manual_non_coloc_6ghz) { | 
|  | 1404 | wpa_dbg(wpa_s, MSG_DEBUG, "Collocated 6 GHz logic is disabled"); | 
|  | 1405 | params.non_coloc_6ghz = 1; | 
|  | 1406 | } | 
|  | 1407 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1408 | scan_params = ¶ms; | 
|  | 1409 |  | 
|  | 1410 | scan: | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1411 | #ifdef CONFIG_P2P | 
|  | 1412 | /* | 
|  | 1413 | * If the driver does not support multi-channel concurrency and a | 
|  | 1414 | * virtual interface that shares the same radio with the wpa_s interface | 
|  | 1415 | * is operating there may not be need to scan other channels apart from | 
|  | 1416 | * the current operating channel on the other virtual interface. Filter | 
|  | 1417 | * out other channels in case we are trying to find a connection for a | 
|  | 1418 | * station interface when we are not configured to prefer station | 
|  | 1419 | * connection and a concurrent operation is already in process. | 
|  | 1420 | */ | 
| Dmitry Shmidt | 01904cf | 2013-12-05 11:08:35 -0800 | [diff] [blame] | 1421 | if (wpa_s->scan_for_connection && | 
|  | 1422 | wpa_s->last_scan_req == NORMAL_SCAN_REQ && | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1423 | !scan_params->freqs && !params.freqs && | 
|  | 1424 | wpas_is_p2p_prioritized(wpa_s) && | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1425 | wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && | 
|  | 1426 | non_p2p_network_enabled(wpa_s)) { | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 1427 | unsigned int num = wpa_s->num_multichan_concurrent; | 
|  | 1428 |  | 
|  | 1429 | params.freqs = os_calloc(num + 1, sizeof(int)); | 
|  | 1430 | if (params.freqs) { | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 1431 | /* | 
|  | 1432 | * Exclude the operating frequency of the current | 
|  | 1433 | * interface since we're looking to transition off of | 
|  | 1434 | * it. | 
|  | 1435 | */ | 
|  | 1436 | num = get_shared_radio_freqs(wpa_s, params.freqs, num, | 
|  | 1437 | true); | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 1438 | if (num > 0 && num == wpa_s->num_multichan_concurrent) { | 
|  | 1439 | wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used"); | 
|  | 1440 | } else { | 
|  | 1441 | os_free(params.freqs); | 
|  | 1442 | params.freqs = NULL; | 
|  | 1443 | } | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1444 | } | 
|  | 1445 | } | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 1446 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 1447 | if (!params.freqs && is_6ghz_supported(wpa_s) && | 
|  | 1448 | (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning)) | 
|  | 1449 | wpas_p2p_scan_freqs(wpa_s, ¶ms, true); | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1450 | #endif /* CONFIG_P2P */ | 
|  | 1451 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1452 | ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1453 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1454 | if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && | 
|  | 1455 | !wpa_s->manual_scan_freqs) { | 
|  | 1456 | /* Restore manual_scan_freqs for the next attempt */ | 
|  | 1457 | wpa_s->manual_scan_freqs = params.freqs; | 
|  | 1458 | params.freqs = NULL; | 
|  | 1459 | } | 
|  | 1460 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1461 | wpabuf_free(extra_ie); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1462 | os_free(params.freqs); | 
|  | 1463 | os_free(params.filter_ssids); | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 1464 | os_free(params.mac_addr); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1465 |  | 
|  | 1466 | if (ret) { | 
|  | 1467 | wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 1468 | if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state) | 
|  | 1469 | wpa_supplicant_set_state(wpa_s, | 
|  | 1470 | wpa_s->scan_prev_wpa_state); | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1471 | /* Restore scan_req since we will try to scan again */ | 
| Dmitry Shmidt | 01904cf | 2013-12-05 11:08:35 -0800 | [diff] [blame] | 1472 | wpa_s->scan_req = wpa_s->last_scan_req; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1473 | wpa_supplicant_req_scan(wpa_s, 1, 0); | 
| Dmitry Shmidt | d5e4923 | 2012-12-03 15:08:10 -0800 | [diff] [blame] | 1474 | } else { | 
|  | 1475 | wpa_s->scan_for_connection = 0; | 
| Dmitry Shmidt | 2f74e36 | 2015-01-21 13:19:05 -0800 | [diff] [blame] | 1476 | #ifdef CONFIG_INTERWORKING | 
|  | 1477 | wpa_s->interworking_fast_assoc_tried = 0; | 
|  | 1478 | #endif /* CONFIG_INTERWORKING */ | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 1479 | wpa_s->next_scan_bssid_wildcard_ssid = 0; | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 1480 | if (params.bssid) | 
|  | 1481 | os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1482 | } | 
|  | 1483 | } | 
|  | 1484 |  | 
|  | 1485 |  | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 1486 | void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec) | 
|  | 1487 | { | 
| Dmitry Shmidt | fa3fc4a | 2013-11-21 13:34:38 -0800 | [diff] [blame] | 1488 | struct os_reltime remaining, new_int; | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 1489 | int cancelled; | 
|  | 1490 |  | 
|  | 1491 | cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL, | 
|  | 1492 | &remaining); | 
|  | 1493 |  | 
|  | 1494 | new_int.sec = sec; | 
|  | 1495 | new_int.usec = 0; | 
| Dmitry Shmidt | fa3fc4a | 2013-11-21 13:34:38 -0800 | [diff] [blame] | 1496 | if (cancelled && os_reltime_before(&remaining, &new_int)) { | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 1497 | new_int.sec = remaining.sec; | 
|  | 1498 | new_int.usec = remaining.usec; | 
|  | 1499 | } | 
|  | 1500 |  | 
| Dmitry Shmidt | 051af73 | 2013-10-22 13:52:46 -0700 | [diff] [blame] | 1501 | if (cancelled) { | 
|  | 1502 | eloop_register_timeout(new_int.sec, new_int.usec, | 
|  | 1503 | wpa_supplicant_scan, wpa_s, NULL); | 
|  | 1504 | } | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 1505 | wpa_s->scan_interval = sec; | 
|  | 1506 | } | 
|  | 1507 |  | 
|  | 1508 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1509 | /** | 
|  | 1510 | * wpa_supplicant_req_scan - Schedule a scan for neighboring access points | 
|  | 1511 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 1512 | * @sec: Number of seconds after which to scan | 
|  | 1513 | * @usec: Number of microseconds after which to scan | 
|  | 1514 | * | 
|  | 1515 | * This function is used to schedule a scan for neighboring access points after | 
|  | 1516 | * the specified time. | 
|  | 1517 | */ | 
|  | 1518 | void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) | 
|  | 1519 | { | 
| Dmitry Shmidt | 203eadb | 2015-03-05 14:16:04 -0800 | [diff] [blame] | 1520 | int res; | 
|  | 1521 |  | 
|  | 1522 | if (wpa_s->p2p_mgmt) { | 
|  | 1523 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1524 | "Ignore scan request (%d.%06d sec) on p2p_mgmt interface", | 
|  | 1525 | sec, usec); | 
|  | 1526 | return; | 
|  | 1527 | } | 
|  | 1528 |  | 
|  | 1529 | res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, | 
|  | 1530 | NULL); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1531 | if (res == 1) { | 
|  | 1532 | wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec", | 
| Dmitry Shmidt | e0e48dc | 2013-11-18 12:00:06 -0800 | [diff] [blame] | 1533 | sec, usec); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 1534 | } else if (res == 0) { | 
|  | 1535 | wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner", | 
|  | 1536 | sec, usec); | 
|  | 1537 | } else { | 
|  | 1538 | wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec", | 
|  | 1539 | sec, usec); | 
|  | 1540 | eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1541 | } | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1542 | } | 
|  | 1543 |  | 
|  | 1544 |  | 
|  | 1545 | /** | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1546 | * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan | 
|  | 1547 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 1548 | * @sec: Number of seconds after which to scan | 
|  | 1549 | * @usec: Number of microseconds after which to scan | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1550 | * Returns: 0 on success or -1 otherwise | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1551 | * | 
|  | 1552 | * This function is used to schedule periodic scans for neighboring | 
|  | 1553 | * access points after the specified time. | 
|  | 1554 | */ | 
|  | 1555 | int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, | 
|  | 1556 | int sec, int usec) | 
|  | 1557 | { | 
|  | 1558 | if (!wpa_s->sched_scan_supported) | 
|  | 1559 | return -1; | 
|  | 1560 |  | 
|  | 1561 | eloop_register_timeout(sec, usec, | 
|  | 1562 | wpa_supplicant_delayed_sched_scan_timeout, | 
|  | 1563 | wpa_s, NULL); | 
|  | 1564 |  | 
|  | 1565 | return 0; | 
|  | 1566 | } | 
|  | 1567 |  | 
|  | 1568 |  | 
| Dmitry Shmidt | ebd93af | 2017-02-21 13:40:44 -0800 | [diff] [blame] | 1569 | static void | 
|  | 1570 | wpa_scan_set_relative_rssi_params(struct wpa_supplicant *wpa_s, | 
|  | 1571 | struct wpa_driver_scan_params *params) | 
|  | 1572 | { | 
|  | 1573 | if (wpa_s->wpa_state != WPA_COMPLETED || | 
|  | 1574 | !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI) || | 
|  | 1575 | wpa_s->srp.relative_rssi_set == 0) | 
|  | 1576 | return; | 
|  | 1577 |  | 
|  | 1578 | params->relative_rssi_set = 1; | 
|  | 1579 | params->relative_rssi = wpa_s->srp.relative_rssi; | 
|  | 1580 |  | 
|  | 1581 | if (wpa_s->srp.relative_adjust_rssi == 0) | 
|  | 1582 | return; | 
|  | 1583 |  | 
|  | 1584 | params->relative_adjust_band = wpa_s->srp.relative_adjust_band; | 
|  | 1585 | params->relative_adjust_rssi = wpa_s->srp.relative_adjust_rssi; | 
|  | 1586 | } | 
|  | 1587 |  | 
|  | 1588 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1589 | /** | 
|  | 1590 | * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan | 
|  | 1591 | * @wpa_s: Pointer to wpa_supplicant data | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1592 | * Returns: 0 is sched_scan was started or -1 otherwise | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1593 | * | 
|  | 1594 | * This function is used to schedule periodic scans for neighboring | 
|  | 1595 | * access points repeating the scan continuously. | 
|  | 1596 | */ | 
|  | 1597 | int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) | 
|  | 1598 | { | 
|  | 1599 | struct wpa_driver_scan_params params; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1600 | struct wpa_driver_scan_params *scan_params; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1601 | enum wpa_states prev_state; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1602 | struct wpa_ssid *ssid = NULL; | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1603 | struct wpabuf *extra_ie = NULL; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1604 | int ret; | 
|  | 1605 | unsigned int max_sched_scan_ssids; | 
|  | 1606 | int wildcard = 0; | 
|  | 1607 | int need_ssids; | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 1608 | struct sched_scan_plan scan_plan; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1609 |  | 
|  | 1610 | if (!wpa_s->sched_scan_supported) | 
|  | 1611 | return -1; | 
|  | 1612 |  | 
|  | 1613 | if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) | 
|  | 1614 | max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; | 
|  | 1615 | else | 
|  | 1616 | max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1617 | if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1618 | return -1; | 
|  | 1619 |  | 
| Dmitry Shmidt | 9839ecd | 2016-11-07 11:05:47 -0800 | [diff] [blame] | 1620 | wpa_s->sched_scan_stop_req = 0; | 
|  | 1621 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1622 | if (wpa_s->sched_scanning) { | 
|  | 1623 | wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); | 
|  | 1624 | return 0; | 
|  | 1625 | } | 
|  | 1626 |  | 
|  | 1627 | need_ssids = 0; | 
|  | 1628 | for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1629 | if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1630 | /* Use wildcard SSID to find this network */ | 
|  | 1631 | wildcard = 1; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1632 | } else if (!wpas_network_disabled(wpa_s, ssid) && | 
|  | 1633 | ssid->ssid_len) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1634 | need_ssids++; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1635 |  | 
|  | 1636 | #ifdef CONFIG_WPS | 
|  | 1637 | if (!wpas_network_disabled(wpa_s, ssid) && | 
|  | 1638 | ssid->key_mgmt == WPA_KEY_MGMT_WPS) { | 
|  | 1639 | /* | 
|  | 1640 | * Normal scan is more reliable and faster for WPS | 
|  | 1641 | * operations and since these are for short periods of | 
|  | 1642 | * time, the benefit of trying to use sched_scan would | 
|  | 1643 | * be limited. | 
|  | 1644 | */ | 
|  | 1645 | wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " | 
|  | 1646 | "sched_scan for WPS"); | 
|  | 1647 | return -1; | 
|  | 1648 | } | 
|  | 1649 | #endif /* CONFIG_WPS */ | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1650 | } | 
|  | 1651 | if (wildcard) | 
|  | 1652 | need_ssids++; | 
|  | 1653 |  | 
|  | 1654 | if (wpa_s->normal_scans < 3 && | 
|  | 1655 | (need_ssids <= wpa_s->max_scan_ssids || | 
|  | 1656 | wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) { | 
|  | 1657 | /* | 
|  | 1658 | * When normal scan can speed up operations, use that for the | 
|  | 1659 | * first operations before starting the sched_scan to allow | 
|  | 1660 | * user space sleep more. We do this only if the normal scan | 
|  | 1661 | * has functionality that is suitable for this or if the | 
|  | 1662 | * sched_scan does not have better support for multiple SSIDs. | 
|  | 1663 | */ | 
|  | 1664 | wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " | 
|  | 1665 | "sched_scan for initial scans (normal_scans=%d)", | 
|  | 1666 | wpa_s->normal_scans); | 
|  | 1667 | return -1; | 
|  | 1668 | } | 
|  | 1669 |  | 
|  | 1670 | os_memset(¶ms, 0, sizeof(params)); | 
|  | 1671 |  | 
|  | 1672 | /* If we can't allocate space for the filters, we just don't filter */ | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 1673 | params.filter_ssids = os_calloc(wpa_s->max_match_sets, | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1674 | sizeof(struct wpa_driver_scan_filter)); | 
|  | 1675 |  | 
|  | 1676 | prev_state = wpa_s->wpa_state; | 
|  | 1677 | if (wpa_s->wpa_state == WPA_DISCONNECTED || | 
|  | 1678 | wpa_s->wpa_state == WPA_INACTIVE) | 
|  | 1679 | wpa_supplicant_set_state(wpa_s, WPA_SCANNING); | 
|  | 1680 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1681 | if (wpa_s->autoscan_params != NULL) { | 
|  | 1682 | scan_params = wpa_s->autoscan_params; | 
|  | 1683 | goto scan; | 
|  | 1684 | } | 
|  | 1685 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1686 | /* Find the starting point from which to continue scanning */ | 
|  | 1687 | ssid = wpa_s->conf->ssid; | 
|  | 1688 | if (wpa_s->prev_sched_ssid) { | 
|  | 1689 | while (ssid) { | 
|  | 1690 | if (ssid == wpa_s->prev_sched_ssid) { | 
|  | 1691 | ssid = ssid->next; | 
|  | 1692 | break; | 
|  | 1693 | } | 
|  | 1694 | ssid = ssid->next; | 
|  | 1695 | } | 
|  | 1696 | } | 
|  | 1697 |  | 
|  | 1698 | if (!ssid || !wpa_s->prev_sched_ssid) { | 
|  | 1699 | wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1700 | wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; | 
|  | 1701 | wpa_s->first_sched_scan = 1; | 
|  | 1702 | ssid = wpa_s->conf->ssid; | 
|  | 1703 | wpa_s->prev_sched_ssid = ssid; | 
|  | 1704 | } | 
|  | 1705 |  | 
|  | 1706 | if (wildcard) { | 
|  | 1707 | wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan"); | 
|  | 1708 | params.num_ssids++; | 
|  | 1709 | } | 
|  | 1710 |  | 
|  | 1711 | while (ssid) { | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1712 | if (wpas_network_disabled(wpa_s, ssid)) | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1713 | goto next; | 
|  | 1714 |  | 
|  | 1715 | if (params.num_filter_ssids < wpa_s->max_match_sets && | 
|  | 1716 | params.filter_ssids && ssid->ssid && ssid->ssid_len) { | 
|  | 1717 | wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s", | 
|  | 1718 | wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
|  | 1719 | os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid, | 
|  | 1720 | ssid->ssid, ssid->ssid_len); | 
|  | 1721 | params.filter_ssids[params.num_filter_ssids].ssid_len = | 
|  | 1722 | ssid->ssid_len; | 
|  | 1723 | params.num_filter_ssids++; | 
|  | 1724 | } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len) | 
|  | 1725 | { | 
|  | 1726 | wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID " | 
|  | 1727 | "filter for sched_scan - drop filter"); | 
|  | 1728 | os_free(params.filter_ssids); | 
|  | 1729 | params.filter_ssids = NULL; | 
|  | 1730 | params.num_filter_ssids = 0; | 
|  | 1731 | } | 
|  | 1732 |  | 
|  | 1733 | if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) { | 
|  | 1734 | if (params.num_ssids == max_sched_scan_ssids) | 
|  | 1735 | break; /* only room for broadcast SSID */ | 
|  | 1736 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1737 | "add to active scan ssid: %s", | 
|  | 1738 | wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); | 
|  | 1739 | params.ssids[params.num_ssids].ssid = | 
|  | 1740 | ssid->ssid; | 
|  | 1741 | params.ssids[params.num_ssids].ssid_len = | 
|  | 1742 | ssid->ssid_len; | 
|  | 1743 | params.num_ssids++; | 
|  | 1744 | if (params.num_ssids >= max_sched_scan_ssids) { | 
|  | 1745 | wpa_s->prev_sched_ssid = ssid; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1746 | do { | 
|  | 1747 | ssid = ssid->next; | 
|  | 1748 | } while (ssid && | 
|  | 1749 | (wpas_network_disabled(wpa_s, ssid) || | 
|  | 1750 | !ssid->scan_ssid)); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1751 | break; | 
|  | 1752 | } | 
|  | 1753 | } | 
|  | 1754 |  | 
|  | 1755 | next: | 
|  | 1756 | wpa_s->prev_sched_ssid = ssid; | 
|  | 1757 | ssid = ssid->next; | 
|  | 1758 | } | 
|  | 1759 |  | 
|  | 1760 | if (params.num_filter_ssids == 0) { | 
|  | 1761 | os_free(params.filter_ssids); | 
|  | 1762 | params.filter_ssids = NULL; | 
|  | 1763 | } | 
|  | 1764 |  | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1765 | extra_ie = wpa_supplicant_extra_ies(wpa_s); | 
|  | 1766 | if (extra_ie) { | 
|  | 1767 | params.extra_ies = wpabuf_head(extra_ie); | 
|  | 1768 | params.extra_ies_len = wpabuf_len(extra_ie); | 
|  | 1769 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1770 |  | 
| Dmitry Shmidt | 1846323 | 2014-01-24 12:29:41 -0800 | [diff] [blame] | 1771 | if (wpa_s->conf->filter_rssi) | 
|  | 1772 | params.filter_rssi = wpa_s->conf->filter_rssi; | 
|  | 1773 |  | 
| Dmitry Shmidt | 661b4f7 | 2014-09-29 14:58:27 -0700 | [diff] [blame] | 1774 | /* See if user specified frequencies. If so, scan only those. */ | 
|  | 1775 | if (wpa_s->conf->freq_list && !params.freqs) { | 
|  | 1776 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1777 | "Optimize scan based on conf->freq_list"); | 
|  | 1778 | int_array_concat(¶ms.freqs, wpa_s->conf->freq_list); | 
|  | 1779 | } | 
|  | 1780 |  | 
| Hai Shalom | ce48b4a | 2018-09-05 11:41:35 -0700 | [diff] [blame] | 1781 | #ifdef CONFIG_MBO | 
|  | 1782 | if (wpa_s->enable_oce & OCE_STA) | 
|  | 1783 | params.oce_scan = 1; | 
|  | 1784 | #endif /* CONFIG_MBO */ | 
|  | 1785 |  | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1786 | scan_params = ¶ms; | 
|  | 1787 |  | 
|  | 1788 | scan: | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 1789 | wpa_s->sched_scan_timed_out = 0; | 
|  | 1790 |  | 
|  | 1791 | /* | 
|  | 1792 | * We cannot support multiple scan plans if the scan request includes | 
|  | 1793 | * too many SSID's, so in this case use only the last scan plan and make | 
|  | 1794 | * it run infinitely. It will be stopped by the timeout. | 
|  | 1795 | */ | 
|  | 1796 | if (wpa_s->sched_scan_plans_num == 1 || | 
|  | 1797 | (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) { | 
|  | 1798 | params.sched_scan_plans = wpa_s->sched_scan_plans; | 
|  | 1799 | params.sched_scan_plans_num = wpa_s->sched_scan_plans_num; | 
|  | 1800 | } else if (wpa_s->sched_scan_plans_num > 1) { | 
|  | 1801 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1802 | "Too many SSIDs. Default to using single scheduled_scan plan"); | 
|  | 1803 | params.sched_scan_plans = | 
|  | 1804 | &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num - | 
|  | 1805 | 1]; | 
|  | 1806 | params.sched_scan_plans_num = 1; | 
|  | 1807 | } else { | 
|  | 1808 | if (wpa_s->conf->sched_scan_interval) | 
|  | 1809 | scan_plan.interval = wpa_s->conf->sched_scan_interval; | 
|  | 1810 | else | 
|  | 1811 | scan_plan.interval = 10; | 
|  | 1812 |  | 
|  | 1813 | if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) { | 
|  | 1814 | wpa_printf(MSG_WARNING, | 
|  | 1815 | "Scan interval too long(%u), use the maximum allowed(%u)", | 
|  | 1816 | scan_plan.interval, | 
|  | 1817 | wpa_s->max_sched_scan_plan_interval); | 
|  | 1818 | scan_plan.interval = | 
|  | 1819 | wpa_s->max_sched_scan_plan_interval; | 
|  | 1820 | } | 
|  | 1821 |  | 
|  | 1822 | scan_plan.iterations = 0; | 
|  | 1823 | params.sched_scan_plans = &scan_plan; | 
|  | 1824 | params.sched_scan_plans_num = 1; | 
|  | 1825 | } | 
|  | 1826 |  | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 1827 | params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay; | 
|  | 1828 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1829 | if (ssid || !wpa_s->first_sched_scan) { | 
|  | 1830 | wpa_dbg(wpa_s, MSG_DEBUG, | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 1831 | "Starting sched scan after %u seconds: interval %u timeout %d", | 
|  | 1832 | params.sched_scan_start_delay, | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 1833 | params.sched_scan_plans[0].interval, | 
|  | 1834 | wpa_s->sched_scan_timeout); | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 1835 | } else { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 1836 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 1837 | "Starting sched scan after %u seconds (no timeout)", | 
|  | 1838 | params.sched_scan_start_delay); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1839 | } | 
|  | 1840 |  | 
| Dmitry Shmidt | b6e9aaf | 2013-05-20 14:49:44 -0700 | [diff] [blame] | 1841 | wpa_setband_scan_freqs(wpa_s, scan_params); | 
|  | 1842 |  | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 1843 | if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) && | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 1844 | wpa_s->wpa_state <= WPA_SCANNING) | 
|  | 1845 | wpa_setup_mac_addr_rand_params(¶ms, | 
|  | 1846 | wpa_s->mac_addr_sched_scan); | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 1847 |  | 
| Dmitry Shmidt | ebd93af | 2017-02-21 13:40:44 -0800 | [diff] [blame] | 1848 | wpa_scan_set_relative_rssi_params(wpa_s, scan_params); | 
|  | 1849 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 1850 | ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params); | 
| Dmitry Shmidt | 61d9df3 | 2012-08-29 16:22:06 -0700 | [diff] [blame] | 1851 | wpabuf_free(extra_ie); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1852 | os_free(params.filter_ssids); | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 1853 | os_free(params.mac_addr); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1854 | if (ret) { | 
|  | 1855 | wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); | 
|  | 1856 | if (prev_state != wpa_s->wpa_state) | 
|  | 1857 | wpa_supplicant_set_state(wpa_s, prev_state); | 
|  | 1858 | return ret; | 
|  | 1859 | } | 
|  | 1860 |  | 
|  | 1861 | /* If we have more SSIDs to scan, add a timeout so we scan them too */ | 
|  | 1862 | if (ssid || !wpa_s->first_sched_scan) { | 
|  | 1863 | wpa_s->sched_scan_timed_out = 0; | 
|  | 1864 | eloop_register_timeout(wpa_s->sched_scan_timeout, 0, | 
|  | 1865 | wpa_supplicant_sched_scan_timeout, | 
|  | 1866 | wpa_s, NULL); | 
|  | 1867 | wpa_s->first_sched_scan = 0; | 
|  | 1868 | wpa_s->sched_scan_timeout /= 2; | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 1869 | params.sched_scan_plans[0].interval *= 2; | 
|  | 1870 | if ((unsigned int) wpa_s->sched_scan_timeout < | 
|  | 1871 | params.sched_scan_plans[0].interval || | 
|  | 1872 | params.sched_scan_plans[0].interval > | 
|  | 1873 | wpa_s->max_sched_scan_plan_interval) { | 
|  | 1874 | params.sched_scan_plans[0].interval = 10; | 
| Dmitry Shmidt | 2f02319 | 2013-03-12 12:44:17 -0700 | [diff] [blame] | 1875 | wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; | 
|  | 1876 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1877 | } | 
|  | 1878 |  | 
| Dmitry Shmidt | 2f02319 | 2013-03-12 12:44:17 -0700 | [diff] [blame] | 1879 | /* If there is no more ssids, start next time from the beginning */ | 
|  | 1880 | if (!ssid) | 
|  | 1881 | wpa_s->prev_sched_ssid = NULL; | 
|  | 1882 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1883 | return 0; | 
|  | 1884 | } | 
|  | 1885 |  | 
|  | 1886 |  | 
|  | 1887 | /** | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1888 | * wpa_supplicant_cancel_scan - Cancel a scheduled scan request | 
|  | 1889 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 1890 | * | 
|  | 1891 | * This function is used to cancel a scan request scheduled with | 
|  | 1892 | * wpa_supplicant_req_scan(). | 
|  | 1893 | */ | 
|  | 1894 | void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) | 
|  | 1895 | { | 
|  | 1896 | wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request"); | 
|  | 1897 | eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1898 | } | 
|  | 1899 |  | 
|  | 1900 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1901 | /** | 
| Dmitry Shmidt | c2ebb4b | 2013-07-24 12:57:51 -0700 | [diff] [blame] | 1902 | * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan | 
|  | 1903 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 1904 | * | 
|  | 1905 | * This function is used to stop a delayed scheduled scan. | 
|  | 1906 | */ | 
|  | 1907 | void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s) | 
|  | 1908 | { | 
|  | 1909 | if (!wpa_s->sched_scan_supported) | 
|  | 1910 | return; | 
|  | 1911 |  | 
|  | 1912 | wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan"); | 
|  | 1913 | eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout, | 
|  | 1914 | wpa_s, NULL); | 
|  | 1915 | } | 
|  | 1916 |  | 
|  | 1917 |  | 
|  | 1918 | /** | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1919 | * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans | 
|  | 1920 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 1921 | * | 
|  | 1922 | * This function is used to stop a periodic scheduled scan. | 
|  | 1923 | */ | 
|  | 1924 | void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s) | 
|  | 1925 | { | 
|  | 1926 | if (!wpa_s->sched_scanning) | 
|  | 1927 | return; | 
|  | 1928 |  | 
| Dmitry Shmidt | 9839ecd | 2016-11-07 11:05:47 -0800 | [diff] [blame] | 1929 | if (wpa_s->sched_scanning) | 
|  | 1930 | wpa_s->sched_scan_stop_req = 1; | 
|  | 1931 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 1932 | wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan"); | 
|  | 1933 | eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL); | 
|  | 1934 | wpa_supplicant_stop_sched_scan(wpa_s); | 
|  | 1935 | } | 
|  | 1936 |  | 
|  | 1937 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1938 | /** | 
|  | 1939 | * wpa_supplicant_notify_scanning - Indicate possible scan state change | 
|  | 1940 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 1941 | * @scanning: Whether scanning is currently in progress | 
|  | 1942 | * | 
|  | 1943 | * This function is to generate scanning notifycations. It is called whenever | 
|  | 1944 | * there may have been a change in scanning (scan started, completed, stopped). | 
|  | 1945 | * wpas_notify_scanning() is called whenever the scanning state changed from the | 
|  | 1946 | * previously notified state. | 
|  | 1947 | */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1948 | void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, | 
|  | 1949 | int scanning) | 
|  | 1950 | { | 
|  | 1951 | if (wpa_s->scanning != scanning) { | 
|  | 1952 | wpa_s->scanning = scanning; | 
|  | 1953 | wpas_notify_scanning(wpa_s); | 
|  | 1954 | } | 
|  | 1955 | } | 
|  | 1956 |  | 
|  | 1957 |  | 
|  | 1958 | static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) | 
|  | 1959 | { | 
|  | 1960 | int rate = 0; | 
|  | 1961 | const u8 *ie; | 
|  | 1962 | int i; | 
|  | 1963 |  | 
|  | 1964 | ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); | 
|  | 1965 | for (i = 0; ie && i < ie[1]; i++) { | 
|  | 1966 | if ((ie[i + 2] & 0x7f) > rate) | 
|  | 1967 | rate = ie[i + 2] & 0x7f; | 
|  | 1968 | } | 
|  | 1969 |  | 
|  | 1970 | ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); | 
|  | 1971 | for (i = 0; ie && i < ie[1]; i++) { | 
|  | 1972 | if ((ie[i + 2] & 0x7f) > rate) | 
|  | 1973 | rate = ie[i + 2] & 0x7f; | 
|  | 1974 | } | 
|  | 1975 |  | 
|  | 1976 | return rate; | 
|  | 1977 | } | 
|  | 1978 |  | 
|  | 1979 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 1980 | /** | 
|  | 1981 | * wpa_scan_get_ie - Fetch a specified information element from a scan result | 
|  | 1982 | * @res: Scan result entry | 
|  | 1983 | * @ie: Information element identitifier (WLAN_EID_*) | 
|  | 1984 | * Returns: Pointer to the information element (id field) or %NULL if not found | 
|  | 1985 | * | 
|  | 1986 | * This function returns the first matching information element in the scan | 
|  | 1987 | * result. | 
|  | 1988 | */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1989 | const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) | 
|  | 1990 | { | 
| Dmitry Shmidt | 9839ecd | 2016-11-07 11:05:47 -0800 | [diff] [blame] | 1991 | size_t ie_len = res->ie_len; | 
|  | 1992 |  | 
|  | 1993 | /* Use the Beacon frame IEs if res->ie_len is not available */ | 
|  | 1994 | if (!ie_len) | 
|  | 1995 | ie_len = res->beacon_ie_len; | 
|  | 1996 |  | 
|  | 1997 | return get_ie((const u8 *) (res + 1), ie_len, ie); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 1998 | } | 
|  | 1999 |  | 
|  | 2000 |  | 
| Sunil Ravi | 89eba10 | 2022-09-13 21:04:37 -0700 | [diff] [blame] | 2001 | const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type) | 
|  | 2002 | { | 
|  | 2003 | size_t ie_len = res->ie_len; | 
|  | 2004 |  | 
|  | 2005 | /* Use the Beacon frame IEs if res->ie_len is not available */ | 
|  | 2006 | if (!ie_len) | 
|  | 2007 | ie_len = res->beacon_ie_len; | 
|  | 2008 |  | 
|  | 2009 | return get_ml_ie((const u8 *) (res + 1), ie_len, type); | 
|  | 2010 | } | 
|  | 2011 |  | 
|  | 2012 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2013 | /** | 
|  | 2014 | * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result | 
|  | 2015 | * @res: Scan result entry | 
|  | 2016 | * @vendor_type: Vendor type (four octets starting the IE payload) | 
|  | 2017 | * Returns: Pointer to the information element (id field) or %NULL if not found | 
|  | 2018 | * | 
|  | 2019 | * This function returns the first matching information element in the scan | 
|  | 2020 | * result. | 
|  | 2021 | */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2022 | const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, | 
|  | 2023 | u32 vendor_type) | 
|  | 2024 | { | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2025 | const u8 *ies; | 
|  | 2026 | const struct element *elem; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2027 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2028 | ies = (const u8 *) (res + 1); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2029 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2030 | for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, res->ie_len) { | 
|  | 2031 | if (elem->datalen >= 4 && | 
|  | 2032 | vendor_type == WPA_GET_BE32(elem->data)) | 
|  | 2033 | return &elem->id; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2034 | } | 
|  | 2035 |  | 
|  | 2036 | return NULL; | 
|  | 2037 | } | 
|  | 2038 |  | 
|  | 2039 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2040 | /** | 
| Dmitry Shmidt | 9657139 | 2013-10-14 12:54:46 -0700 | [diff] [blame] | 2041 | * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result | 
|  | 2042 | * @res: Scan result entry | 
|  | 2043 | * @vendor_type: Vendor type (four octets starting the IE payload) | 
|  | 2044 | * Returns: Pointer to the information element (id field) or %NULL if not found | 
|  | 2045 | * | 
|  | 2046 | * This function returns the first matching information element in the scan | 
|  | 2047 | * result. | 
|  | 2048 | * | 
|  | 2049 | * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only | 
|  | 2050 | * from Beacon frames instead of either Beacon or Probe Response frames. | 
|  | 2051 | */ | 
|  | 2052 | const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res, | 
|  | 2053 | u32 vendor_type) | 
|  | 2054 | { | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2055 | const u8 *ies; | 
|  | 2056 | const struct element *elem; | 
| Dmitry Shmidt | 9657139 | 2013-10-14 12:54:46 -0700 | [diff] [blame] | 2057 |  | 
|  | 2058 | if (res->beacon_ie_len == 0) | 
|  | 2059 | return NULL; | 
|  | 2060 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2061 | ies = (const u8 *) (res + 1); | 
|  | 2062 | ies += res->ie_len; | 
| Dmitry Shmidt | 9657139 | 2013-10-14 12:54:46 -0700 | [diff] [blame] | 2063 |  | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2064 | for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, | 
|  | 2065 | res->beacon_ie_len) { | 
|  | 2066 | if (elem->datalen >= 4 && | 
|  | 2067 | vendor_type == WPA_GET_BE32(elem->data)) | 
|  | 2068 | return &elem->id; | 
| Dmitry Shmidt | 9657139 | 2013-10-14 12:54:46 -0700 | [diff] [blame] | 2069 | } | 
|  | 2070 |  | 
|  | 2071 | return NULL; | 
|  | 2072 | } | 
|  | 2073 |  | 
|  | 2074 |  | 
|  | 2075 | /** | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2076 | * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result | 
|  | 2077 | * @res: Scan result entry | 
|  | 2078 | * @vendor_type: Vendor type (four octets starting the IE payload) | 
|  | 2079 | * Returns: Pointer to the information element payload or %NULL if not found | 
|  | 2080 | * | 
|  | 2081 | * This function returns concatenated payload of possibly fragmented vendor | 
|  | 2082 | * specific information elements in the scan result. The caller is responsible | 
|  | 2083 | * for freeing the returned buffer. | 
|  | 2084 | */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2085 | struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, | 
|  | 2086 | u32 vendor_type) | 
|  | 2087 | { | 
|  | 2088 | struct wpabuf *buf; | 
|  | 2089 | const u8 *end, *pos; | 
|  | 2090 |  | 
|  | 2091 | buf = wpabuf_alloc(res->ie_len); | 
|  | 2092 | if (buf == NULL) | 
|  | 2093 | return NULL; | 
|  | 2094 |  | 
|  | 2095 | pos = (const u8 *) (res + 1); | 
|  | 2096 | end = pos + res->ie_len; | 
|  | 2097 |  | 
| Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 2098 | while (end - pos > 1) { | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2099 | u8 ie, len; | 
|  | 2100 |  | 
|  | 2101 | ie = pos[0]; | 
|  | 2102 | len = pos[1]; | 
|  | 2103 | if (len > end - pos - 2) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2104 | break; | 
| Hai Shalom | 6084025 | 2021-02-19 19:02:11 -0800 | [diff] [blame] | 2105 | pos += 2; | 
|  | 2106 | if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 && | 
|  | 2107 | vendor_type == WPA_GET_BE32(pos)) | 
|  | 2108 | wpabuf_put_data(buf, pos + 4, len - 4); | 
|  | 2109 | pos += len; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2110 | } | 
|  | 2111 |  | 
|  | 2112 | if (wpabuf_len(buf) == 0) { | 
|  | 2113 | wpabuf_free(buf); | 
|  | 2114 | buf = NULL; | 
|  | 2115 | } | 
|  | 2116 |  | 
|  | 2117 | return buf; | 
|  | 2118 | } | 
|  | 2119 |  | 
|  | 2120 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2121 | /* Compare function for sorting scan results. Return >0 if @b is considered | 
|  | 2122 | * better. */ | 
|  | 2123 | static int wpa_scan_result_compar(const void *a, const void *b) | 
|  | 2124 | { | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2125 | #define MIN(a,b) a < b ? a : b | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2126 | struct wpa_scan_res **_wa = (void *) a; | 
|  | 2127 | struct wpa_scan_res **_wb = (void *) b; | 
|  | 2128 | struct wpa_scan_res *wa = *_wa; | 
|  | 2129 | struct wpa_scan_res *wb = *_wb; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2130 | int wpa_a, wpa_b; | 
|  | 2131 | int snr_a, snr_b, snr_a_full, snr_b_full; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2132 |  | 
|  | 2133 | /* WPA/WPA2 support preferred */ | 
|  | 2134 | wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || | 
|  | 2135 | wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; | 
|  | 2136 | wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || | 
|  | 2137 | wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; | 
|  | 2138 |  | 
|  | 2139 | if (wpa_b && !wpa_a) | 
|  | 2140 | return 1; | 
|  | 2141 | if (!wpa_b && wpa_a) | 
|  | 2142 | return -1; | 
|  | 2143 |  | 
|  | 2144 | /* privacy support preferred */ | 
|  | 2145 | if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && | 
|  | 2146 | (wb->caps & IEEE80211_CAP_PRIVACY)) | 
|  | 2147 | return 1; | 
|  | 2148 | if ((wa->caps & IEEE80211_CAP_PRIVACY) && | 
|  | 2149 | (wb->caps & IEEE80211_CAP_PRIVACY) == 0) | 
|  | 2150 | return -1; | 
|  | 2151 |  | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2152 | if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) { | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2153 | snr_a_full = wa->snr; | 
|  | 2154 | snr_a = MIN(wa->snr, GREAT_SNR); | 
|  | 2155 | snr_b_full = wb->snr; | 
| Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 2156 | snr_b = MIN(wb->snr, GREAT_SNR); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2157 | } else { | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2158 | /* Level is not in dBm, so we can't calculate | 
|  | 2159 | * SNR. Just use raw level (units unknown). */ | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2160 | snr_a = snr_a_full = wa->level; | 
|  | 2161 | snr_b = snr_b_full = wb->level; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2162 | } | 
|  | 2163 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2164 | /* If SNR is close, decide by max rate or frequency band. For cases | 
|  | 2165 | * involving the 6 GHz band, use the throughput estimate irrespective | 
|  | 2166 | * of the SNR difference since the LPI/VLP rules may result in | 
|  | 2167 | * significant differences in SNR for cases where the estimated | 
|  | 2168 | * throughput can be considerably higher with the lower SNR. */ | 
|  | 2169 | if (snr_a && snr_b && (abs(snr_b - snr_a) < 7 || | 
|  | 2170 | is_6ghz_freq(wa->freq) || | 
|  | 2171 | is_6ghz_freq(wb->freq))) { | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2172 | if (wa->est_throughput != wb->est_throughput) | 
| Hai Shalom | 021b0b5 | 2019-04-10 11:17:58 -0700 | [diff] [blame] | 2173 | return (int) wb->est_throughput - | 
|  | 2174 | (int) wa->est_throughput; | 
| Dmitry Shmidt | ebd93af | 2017-02-21 13:40:44 -0800 | [diff] [blame] | 2175 | } | 
|  | 2176 | if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) || | 
|  | 2177 | (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2178 | if (is_6ghz_freq(wa->freq) ^ is_6ghz_freq(wb->freq)) | 
|  | 2179 | return is_6ghz_freq(wa->freq) ? -1 : 1; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2180 | if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq)) | 
|  | 2181 | return IS_5GHZ(wa->freq) ? -1 : 1; | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2182 | } | 
|  | 2183 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2184 | /* all things being equal, use SNR; if SNRs are | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2185 | * identical, use quality values since some drivers may only report | 
|  | 2186 | * that value and leave the signal level zero */ | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2187 | if (snr_b_full == snr_a_full) | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2188 | return wb->qual - wa->qual; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2189 | return snr_b_full - snr_a_full; | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2190 | #undef MIN | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2191 | } | 
|  | 2192 |  | 
|  | 2193 |  | 
|  | 2194 | #ifdef CONFIG_WPS | 
|  | 2195 | /* Compare function for sorting scan results when searching a WPS AP for | 
|  | 2196 | * provisioning. Return >0 if @b is considered better. */ | 
|  | 2197 | static int wpa_scan_result_wps_compar(const void *a, const void *b) | 
|  | 2198 | { | 
|  | 2199 | struct wpa_scan_res **_wa = (void *) a; | 
|  | 2200 | struct wpa_scan_res **_wb = (void *) b; | 
|  | 2201 | struct wpa_scan_res *wa = *_wa; | 
|  | 2202 | struct wpa_scan_res *wb = *_wb; | 
|  | 2203 | int uses_wps_a, uses_wps_b; | 
|  | 2204 | struct wpabuf *wps_a, *wps_b; | 
|  | 2205 | int res; | 
|  | 2206 |  | 
|  | 2207 | /* Optimization - check WPS IE existence before allocated memory and | 
|  | 2208 | * doing full reassembly. */ | 
|  | 2209 | uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL; | 
|  | 2210 | uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL; | 
|  | 2211 | if (uses_wps_a && !uses_wps_b) | 
|  | 2212 | return -1; | 
|  | 2213 | if (!uses_wps_a && uses_wps_b) | 
|  | 2214 | return 1; | 
|  | 2215 |  | 
|  | 2216 | if (uses_wps_a && uses_wps_b) { | 
|  | 2217 | wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE); | 
|  | 2218 | wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE); | 
|  | 2219 | res = wps_ap_priority_compar(wps_a, wps_b); | 
|  | 2220 | wpabuf_free(wps_a); | 
|  | 2221 | wpabuf_free(wps_b); | 
|  | 2222 | if (res) | 
|  | 2223 | return res; | 
|  | 2224 | } | 
|  | 2225 |  | 
|  | 2226 | /* | 
|  | 2227 | * Do not use current AP security policy as a sorting criteria during | 
|  | 2228 | * WPS provisioning step since the AP may get reconfigured at the | 
|  | 2229 | * completion of provisioning. | 
|  | 2230 | */ | 
|  | 2231 |  | 
|  | 2232 | /* all things being equal, use signal level; if signal levels are | 
|  | 2233 | * identical, use quality values since some drivers may only report | 
|  | 2234 | * that value and leave the signal level zero */ | 
|  | 2235 | if (wb->level == wa->level) | 
|  | 2236 | return wb->qual - wa->qual; | 
|  | 2237 | return wb->level - wa->level; | 
|  | 2238 | } | 
|  | 2239 | #endif /* CONFIG_WPS */ | 
|  | 2240 |  | 
|  | 2241 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2242 | static void dump_scan_res(struct wpa_scan_results *scan_res) | 
|  | 2243 | { | 
|  | 2244 | #ifndef CONFIG_NO_STDOUT_DEBUG | 
|  | 2245 | size_t i; | 
|  | 2246 |  | 
|  | 2247 | if (scan_res->res == NULL || scan_res->num == 0) | 
|  | 2248 | return; | 
|  | 2249 |  | 
|  | 2250 | wpa_printf(MSG_EXCESSIVE, "Sorted scan results"); | 
|  | 2251 |  | 
|  | 2252 | for (i = 0; i < scan_res->num; i++) { | 
|  | 2253 | struct wpa_scan_res *r = scan_res->res[i]; | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 2254 | u8 *pos; | 
| Sunil Ravi | a04bd25 | 2022-05-02 22:54:18 -0700 | [diff] [blame] | 2255 | const u8 *ssid_ie, *ssid = NULL; | 
|  | 2256 | size_t ssid_len = 0; | 
|  | 2257 |  | 
|  | 2258 | ssid_ie = wpa_scan_get_ie(r, WLAN_EID_SSID); | 
|  | 2259 | if (ssid_ie) { | 
|  | 2260 | ssid = ssid_ie + 2; | 
|  | 2261 | ssid_len = ssid_ie[1]; | 
|  | 2262 | } | 
|  | 2263 |  | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2264 | if (r->flags & WPA_SCAN_LEVEL_DBM) { | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2265 | int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID); | 
|  | 2266 |  | 
| Sunil Ravi | a04bd25 | 2022-05-02 22:54:18 -0700 | [diff] [blame] | 2267 | wpa_printf(MSG_EXCESSIVE, MACSTR | 
|  | 2268 | " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u", | 
|  | 2269 | MAC2STR(r->bssid), | 
|  | 2270 | wpa_ssid_txt(ssid, ssid_len), | 
|  | 2271 | r->freq, r->qual, | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2272 | r->noise, noise_valid ? "" : "~", r->level, | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2273 | r->snr, r->snr >= GREAT_SNR ? "*" : "", | 
|  | 2274 | r->flags, | 
|  | 2275 | r->age, r->est_throughput); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2276 | } else { | 
| Sunil Ravi | a04bd25 | 2022-05-02 22:54:18 -0700 | [diff] [blame] | 2277 | wpa_printf(MSG_EXCESSIVE, MACSTR | 
|  | 2278 | " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u", | 
|  | 2279 | MAC2STR(r->bssid), | 
|  | 2280 | wpa_ssid_txt(ssid, ssid_len), | 
|  | 2281 | r->freq, r->qual, | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2282 | r->noise, r->level, r->flags, r->age, | 
|  | 2283 | r->est_throughput); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2284 | } | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 2285 | pos = (u8 *) (r + 1); | 
|  | 2286 | if (r->ie_len) | 
|  | 2287 | wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len); | 
|  | 2288 | pos += r->ie_len; | 
|  | 2289 | if (r->beacon_ie_len) | 
|  | 2290 | wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs", | 
|  | 2291 | pos, r->beacon_ie_len); | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2292 | } | 
|  | 2293 | #endif /* CONFIG_NO_STDOUT_DEBUG */ | 
|  | 2294 | } | 
|  | 2295 |  | 
|  | 2296 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2297 | /** | 
|  | 2298 | * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed | 
|  | 2299 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 2300 | * @bssid: BSSID to check | 
|  | 2301 | * Returns: 0 if the BSSID is filtered or 1 if not | 
|  | 2302 | * | 
|  | 2303 | * This function is used to filter out specific BSSIDs from scan reslts mainly | 
|  | 2304 | * for testing purposes (SET bssid_filter ctrl_iface command). | 
|  | 2305 | */ | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 2306 | int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, | 
|  | 2307 | const u8 *bssid) | 
|  | 2308 | { | 
|  | 2309 | size_t i; | 
|  | 2310 |  | 
|  | 2311 | if (wpa_s->bssid_filter == NULL) | 
|  | 2312 | return 1; | 
|  | 2313 |  | 
|  | 2314 | for (i = 0; i < wpa_s->bssid_filter_count; i++) { | 
|  | 2315 | if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid, | 
|  | 2316 | ETH_ALEN) == 0) | 
|  | 2317 | return 1; | 
|  | 2318 | } | 
|  | 2319 |  | 
|  | 2320 | return 0; | 
|  | 2321 | } | 
|  | 2322 |  | 
|  | 2323 |  | 
| Dmitry Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 2324 | void filter_scan_res(struct wpa_supplicant *wpa_s, | 
|  | 2325 | struct wpa_scan_results *res) | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 2326 | { | 
|  | 2327 | size_t i, j; | 
|  | 2328 |  | 
|  | 2329 | if (wpa_s->bssid_filter == NULL) | 
|  | 2330 | return; | 
|  | 2331 |  | 
|  | 2332 | for (i = 0, j = 0; i < res->num; i++) { | 
|  | 2333 | if (wpa_supplicant_filter_bssid_match(wpa_s, | 
|  | 2334 | res->res[i]->bssid)) { | 
|  | 2335 | res->res[j++] = res->res[i]; | 
|  | 2336 | } else { | 
|  | 2337 | os_free(res->res[i]); | 
|  | 2338 | res->res[i] = NULL; | 
|  | 2339 | } | 
|  | 2340 | } | 
|  | 2341 |  | 
|  | 2342 | if (res->num != j) { | 
|  | 2343 | wpa_printf(MSG_DEBUG, "Filtered out %d scan results", | 
|  | 2344 | (int) (res->num - j)); | 
|  | 2345 | res->num = j; | 
|  | 2346 | } | 
|  | 2347 | } | 
|  | 2348 |  | 
|  | 2349 |  | 
| Dmitry Shmidt | 849734c | 2016-05-27 09:59:01 -0700 | [diff] [blame] | 2350 | void scan_snr(struct wpa_scan_res *res) | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2351 | { | 
|  | 2352 | if (res->flags & WPA_SCAN_NOISE_INVALID) { | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2353 | res->noise = is_6ghz_freq(res->freq) ? | 
|  | 2354 | DEFAULT_NOISE_FLOOR_6GHZ : | 
|  | 2355 | (IS_5GHZ(res->freq) ? | 
|  | 2356 | DEFAULT_NOISE_FLOOR_5GHZ : DEFAULT_NOISE_FLOOR_2GHZ); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2357 | } | 
|  | 2358 |  | 
|  | 2359 | if (res->flags & WPA_SCAN_LEVEL_DBM) { | 
|  | 2360 | res->snr = res->level - res->noise; | 
|  | 2361 | } else { | 
|  | 2362 | /* Level is not in dBm, so we can't calculate | 
|  | 2363 | * SNR. Just use raw level (units unknown). */ | 
|  | 2364 | res->snr = res->level; | 
|  | 2365 | } | 
|  | 2366 | } | 
|  | 2367 |  | 
|  | 2368 |  | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2369 | /* Minimum SNR required to achieve a certain bitrate. */ | 
|  | 2370 | struct minsnr_bitrate_entry { | 
|  | 2371 | int minsnr; | 
|  | 2372 | unsigned int bitrate; /* in Mbps */ | 
|  | 2373 | }; | 
|  | 2374 |  | 
|  | 2375 | /* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */ | 
|  | 2376 | static const int vht_mcs = 8; | 
|  | 2377 |  | 
|  | 2378 | static const struct minsnr_bitrate_entry vht20_table[] = { | 
|  | 2379 | { 0, 0 }, | 
|  | 2380 | { 2, 6500 },   /* HT20 MCS0 */ | 
|  | 2381 | { 5, 13000 },  /* HT20 MCS1 */ | 
|  | 2382 | { 9, 19500 },  /* HT20 MCS2 */ | 
|  | 2383 | { 11, 26000 }, /* HT20 MCS3 */ | 
|  | 2384 | { 15, 39000 }, /* HT20 MCS4 */ | 
|  | 2385 | { 18, 52000 }, /* HT20 MCS5 */ | 
|  | 2386 | { 20, 58500 }, /* HT20 MCS6 */ | 
|  | 2387 | { 25, 65000 }, /* HT20 MCS7 */ | 
|  | 2388 | { 29, 78000 }, /* VHT20 MCS8 */ | 
|  | 2389 | { -1, 78000 }  /* SNR > 29 */ | 
|  | 2390 | }; | 
|  | 2391 |  | 
|  | 2392 | static const struct minsnr_bitrate_entry vht40_table[] = { | 
|  | 2393 | { 0, 0 }, | 
|  | 2394 | { 5, 13500 },   /* HT40 MCS0 */ | 
|  | 2395 | { 8, 27000 },   /* HT40 MCS1 */ | 
|  | 2396 | { 12, 40500 },  /* HT40 MCS2 */ | 
|  | 2397 | { 14, 54000 },  /* HT40 MCS3 */ | 
|  | 2398 | { 18, 81000 },  /* HT40 MCS4 */ | 
|  | 2399 | { 21, 108000 }, /* HT40 MCS5 */ | 
|  | 2400 | { 23, 121500 }, /* HT40 MCS6 */ | 
|  | 2401 | { 28, 135000 }, /* HT40 MCS7 */ | 
|  | 2402 | { 32, 162000 }, /* VHT40 MCS8 */ | 
|  | 2403 | { 34, 180000 }, /* VHT40 MCS9 */ | 
|  | 2404 | { -1, 180000 }  /* SNR > 34 */ | 
|  | 2405 | }; | 
|  | 2406 |  | 
|  | 2407 | static const struct minsnr_bitrate_entry vht80_table[] = { | 
|  | 2408 | { 0, 0 }, | 
|  | 2409 | { 8, 29300 },   /* VHT80 MCS0 */ | 
|  | 2410 | { 11, 58500 },  /* VHT80 MCS1 */ | 
|  | 2411 | { 15, 87800 },  /* VHT80 MCS2 */ | 
|  | 2412 | { 17, 117000 }, /* VHT80 MCS3 */ | 
|  | 2413 | { 21, 175500 }, /* VHT80 MCS4 */ | 
|  | 2414 | { 24, 234000 }, /* VHT80 MCS5 */ | 
|  | 2415 | { 26, 263300 }, /* VHT80 MCS6 */ | 
|  | 2416 | { 31, 292500 }, /* VHT80 MCS7 */ | 
|  | 2417 | { 35, 351000 }, /* VHT80 MCS8 */ | 
|  | 2418 | { 37, 390000 }, /* VHT80 MCS9 */ | 
|  | 2419 | { -1, 390000 }  /* SNR > 37 */ | 
|  | 2420 | }; | 
|  | 2421 |  | 
|  | 2422 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2423 | static const struct minsnr_bitrate_entry vht160_table[] = { | 
|  | 2424 | { 0, 0 }, | 
|  | 2425 | { 11, 58500 },  /* VHT160 MCS0 */ | 
|  | 2426 | { 14, 117000 }, /* VHT160 MCS1 */ | 
|  | 2427 | { 18, 175500 }, /* VHT160 MCS2 */ | 
|  | 2428 | { 20, 234000 }, /* VHT160 MCS3 */ | 
|  | 2429 | { 24, 351000 }, /* VHT160 MCS4 */ | 
|  | 2430 | { 27, 468000 }, /* VHT160 MCS5 */ | 
|  | 2431 | { 29, 526500 }, /* VHT160 MCS6 */ | 
|  | 2432 | { 34, 585000 }, /* VHT160 MCS7 */ | 
|  | 2433 | { 38, 702000 }, /* VHT160 MCS8 */ | 
|  | 2434 | { 40, 780000 }, /* VHT160 MCS9 */ | 
|  | 2435 | { -1, 780000 }  /* SNR > 37 */ | 
|  | 2436 | }; | 
|  | 2437 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2438 | /* EHT needs to be enabled in order to achieve MCS12 and MCS13 rates. */ | 
|  | 2439 | #define EHT_MCS 12 | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2440 |  | 
|  | 2441 | static const struct minsnr_bitrate_entry he20_table[] = { | 
|  | 2442 | { 0, 0 }, | 
|  | 2443 | { 2, 8600 },    /* HE20 MCS0 */ | 
|  | 2444 | { 5, 17200 },   /* HE20 MCS1 */ | 
|  | 2445 | { 9, 25800 },   /* HE20 MCS2 */ | 
|  | 2446 | { 11, 34400 },  /* HE20 MCS3 */ | 
|  | 2447 | { 15, 51600 },  /* HE20 MCS4 */ | 
|  | 2448 | { 18, 68800 },  /* HE20 MCS5 */ | 
|  | 2449 | { 20, 77400 },  /* HE20 MCS6 */ | 
|  | 2450 | { 25, 86000 },  /* HE20 MCS7 */ | 
|  | 2451 | { 29, 103200 }, /* HE20 MCS8 */ | 
|  | 2452 | { 31, 114700 }, /* HE20 MCS9 */ | 
|  | 2453 | { 34, 129000 }, /* HE20 MCS10 */ | 
|  | 2454 | { 36, 143400 }, /* HE20 MCS11 */ | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2455 | { 39, 154900 }, /* EHT20 MCS12 */ | 
|  | 2456 | { 42, 172100 }, /* EHT20 MCS13 */ | 
|  | 2457 | { -1, 172100 }  /* SNR > 42 */ | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2458 | }; | 
|  | 2459 |  | 
|  | 2460 | static const struct minsnr_bitrate_entry he40_table[] = { | 
|  | 2461 | { 0, 0 }, | 
|  | 2462 | { 5, 17200 },   /* HE40 MCS0 */ | 
|  | 2463 | { 8, 34400 },   /* HE40 MCS1 */ | 
|  | 2464 | { 12, 51600 },  /* HE40 MCS2 */ | 
|  | 2465 | { 14, 68800 },  /* HE40 MCS3 */ | 
|  | 2466 | { 18, 103200 }, /* HE40 MCS4 */ | 
|  | 2467 | { 21, 137600 }, /* HE40 MCS5 */ | 
|  | 2468 | { 23, 154900 }, /* HE40 MCS6 */ | 
|  | 2469 | { 28, 172100 }, /* HE40 MCS7 */ | 
|  | 2470 | { 32, 206500 }, /* HE40 MCS8 */ | 
|  | 2471 | { 34, 229400 }, /* HE40 MCS9 */ | 
|  | 2472 | { 37, 258100 }, /* HE40 MCS10 */ | 
|  | 2473 | { 39, 286800 }, /* HE40 MCS11 */ | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2474 | { 42, 309500 }, /* EHT40 MCS12 */ | 
|  | 2475 | { 45, 344100 }, /* EHT40 MCS13 */ | 
|  | 2476 | { -1, 344100 }  /* SNR > 45 */ | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2477 | }; | 
|  | 2478 |  | 
|  | 2479 | static const struct minsnr_bitrate_entry he80_table[] = { | 
|  | 2480 | { 0, 0 }, | 
|  | 2481 | { 8, 36000 },   /* HE80 MCS0 */ | 
|  | 2482 | { 11, 72100 },  /* HE80 MCS1 */ | 
|  | 2483 | { 15, 108100 }, /* HE80 MCS2 */ | 
|  | 2484 | { 17, 144100 }, /* HE80 MCS3 */ | 
|  | 2485 | { 21, 216200 }, /* HE80 MCS4 */ | 
|  | 2486 | { 24, 288200 }, /* HE80 MCS5 */ | 
|  | 2487 | { 26, 324300 }, /* HE80 MCS6 */ | 
|  | 2488 | { 31, 360300 }, /* HE80 MCS7 */ | 
|  | 2489 | { 35, 432400 }, /* HE80 MCS8 */ | 
|  | 2490 | { 37, 480400 }, /* HE80 MCS9 */ | 
|  | 2491 | { 40, 540400 }, /* HE80 MCS10 */ | 
|  | 2492 | { 42, 600500 }, /* HE80 MCS11 */ | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2493 | { 45, 648500 }, /* EHT80 MCS12 */ | 
|  | 2494 | { 48, 720600 }, /* EHT80 MCS13 */ | 
|  | 2495 | { -1, 720600 }  /* SNR > 48 */ | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2496 | }; | 
|  | 2497 |  | 
|  | 2498 |  | 
|  | 2499 | static const struct minsnr_bitrate_entry he160_table[] = { | 
|  | 2500 | { 0, 0 }, | 
|  | 2501 | { 11, 72100 },   /* HE160 MCS0 */ | 
|  | 2502 | { 14, 144100 },  /* HE160 MCS1 */ | 
|  | 2503 | { 18, 216200 },  /* HE160 MCS2 */ | 
|  | 2504 | { 20, 288200 },  /* HE160 MCS3 */ | 
|  | 2505 | { 24, 432400 },  /* HE160 MCS4 */ | 
|  | 2506 | { 27, 576500 },  /* HE160 MCS5 */ | 
|  | 2507 | { 29, 648500 },  /* HE160 MCS6 */ | 
|  | 2508 | { 34, 720600 },  /* HE160 MCS7 */ | 
|  | 2509 | { 38, 864700 },  /* HE160 MCS8 */ | 
|  | 2510 | { 40, 960800 },  /* HE160 MCS9 */ | 
|  | 2511 | { 43, 1080900 }, /* HE160 MCS10 */ | 
|  | 2512 | { 45, 1201000 }, /* HE160 MCS11 */ | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2513 | { 48, 1297100 }, /* EHT160 MCS12 */ | 
|  | 2514 | { 51, 1441200 }, /* EHT160 MCS13 */ | 
|  | 2515 | { -1, 1441200 }  /* SNR > 51 */ | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2516 | }; | 
|  | 2517 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2518 | /* See IEEE P802.11be/D2.0, Table 36-86: EHT-MCSs for 4x996-tone RU, NSS,u = 1 | 
|  | 2519 | */ | 
|  | 2520 | static const struct minsnr_bitrate_entry eht320_table[] = { | 
|  | 2521 | { 0, 0 }, | 
|  | 2522 | { 14, 144100 },   /* EHT320 MCS0 */ | 
|  | 2523 | { 17, 288200 },   /* EHT320 MCS1 */ | 
|  | 2524 | { 21, 432400 },   /* EHT320 MCS2 */ | 
|  | 2525 | { 23, 576500 },   /* EHT320 MCS3 */ | 
|  | 2526 | { 27, 864700 },   /* EHT320 MCS4 */ | 
|  | 2527 | { 30, 1152900 },  /* EHT320 MCS5 */ | 
|  | 2528 | { 32, 1297100 },  /* EHT320 MCS6 */ | 
|  | 2529 | { 37, 1441200 },  /* EHT320 MCS7 */ | 
|  | 2530 | { 41, 1729400 },  /* EHT320 MCS8 */ | 
|  | 2531 | { 43, 1921500 },  /* EHT320 MCS9 */ | 
|  | 2532 | { 46, 2161800 },  /* EHT320 MCS10 */ | 
|  | 2533 | { 48, 2401900 },  /* EHT320 MCS11 */ | 
|  | 2534 | { 51, 2594100 },  /* EHT320 MCS12 */ | 
|  | 2535 | { 54, 2882400 },  /* EHT320 MCS13 */ | 
|  | 2536 | { -1, 2882400 }   /* SNR > 54 */ | 
|  | 2537 | }; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2538 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2539 | static unsigned int interpolate_rate(int snr, int snr0, int snr1, | 
|  | 2540 | int rate0, int rate1) | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2541 | { | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2542 | return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2543 | } | 
|  | 2544 |  | 
|  | 2545 |  | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2546 | static unsigned int max_rate(const struct minsnr_bitrate_entry table[], | 
|  | 2547 | int snr, bool vht) | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2548 | { | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2549 | const struct minsnr_bitrate_entry *prev, *entry = table; | 
|  | 2550 |  | 
|  | 2551 | while ((entry->minsnr != -1) && | 
|  | 2552 | (snr >= entry->minsnr) && | 
|  | 2553 | (vht || entry - table <= vht_mcs)) | 
|  | 2554 | entry++; | 
|  | 2555 | if (entry == table) | 
|  | 2556 | return entry->bitrate; | 
|  | 2557 | prev = entry - 1; | 
|  | 2558 | if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs)) | 
|  | 2559 | return prev->bitrate; | 
|  | 2560 | return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate, | 
|  | 2561 | entry->bitrate); | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2562 | } | 
|  | 2563 |  | 
|  | 2564 |  | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2565 | static unsigned int max_ht20_rate(int snr, bool vht) | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2566 | { | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2567 | return max_rate(vht20_table, snr, vht); | 
|  | 2568 | } | 
|  | 2569 |  | 
|  | 2570 |  | 
|  | 2571 | static unsigned int max_ht40_rate(int snr, bool vht) | 
|  | 2572 | { | 
|  | 2573 | return max_rate(vht40_table, snr, vht); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2574 | } | 
|  | 2575 |  | 
|  | 2576 |  | 
|  | 2577 | static unsigned int max_vht80_rate(int snr) | 
|  | 2578 | { | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2579 | return max_rate(vht80_table, snr, 1); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2580 | } | 
|  | 2581 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2582 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2583 | static unsigned int max_vht160_rate(int snr) | 
|  | 2584 | { | 
|  | 2585 | return max_rate(vht160_table, snr, 1); | 
|  | 2586 | } | 
|  | 2587 |  | 
|  | 2588 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2589 | static unsigned int max_he_eht_rate(const struct minsnr_bitrate_entry table[], | 
|  | 2590 | int snr, bool eht) | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2591 | { | 
|  | 2592 | const struct minsnr_bitrate_entry *prev, *entry = table; | 
|  | 2593 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2594 | while (entry->minsnr != -1 && snr >= entry->minsnr && | 
|  | 2595 | (eht || entry - table <= EHT_MCS)) | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2596 | entry++; | 
|  | 2597 | if (entry == table) | 
|  | 2598 | return 0; | 
|  | 2599 | prev = entry - 1; | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2600 | if (entry->minsnr == -1 || (!eht && entry - table > EHT_MCS)) | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2601 | return prev->bitrate; | 
|  | 2602 | return interpolate_rate(snr, prev->minsnr, entry->minsnr, | 
|  | 2603 | prev->bitrate, entry->bitrate); | 
|  | 2604 | } | 
|  | 2605 |  | 
|  | 2606 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2607 | unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, | 
|  | 2608 | const u8 *ies, size_t ies_len, int rate, | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2609 | int snr, int freq) | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2610 | { | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2611 | struct hostapd_hw_modes *hw_mode; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2612 | unsigned int est, tmp; | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2613 | const u8 *ie; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2614 |  | 
|  | 2615 | /* Limit based on estimated SNR */ | 
|  | 2616 | if (rate > 1 * 2 && snr < 1) | 
|  | 2617 | rate = 1 * 2; | 
|  | 2618 | else if (rate > 2 * 2 && snr < 4) | 
|  | 2619 | rate = 2 * 2; | 
|  | 2620 | else if (rate > 6 * 2 && snr < 5) | 
|  | 2621 | rate = 6 * 2; | 
|  | 2622 | else if (rate > 9 * 2 && snr < 6) | 
|  | 2623 | rate = 9 * 2; | 
|  | 2624 | else if (rate > 12 * 2 && snr < 7) | 
|  | 2625 | rate = 12 * 2; | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2626 | else if (rate > 12 * 2 && snr < 8) | 
|  | 2627 | rate = 14 * 2; | 
|  | 2628 | else if (rate > 12 * 2 && snr < 9) | 
|  | 2629 | rate = 16 * 2; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2630 | else if (rate > 18 * 2 && snr < 10) | 
|  | 2631 | rate = 18 * 2; | 
|  | 2632 | else if (rate > 24 * 2 && snr < 11) | 
|  | 2633 | rate = 24 * 2; | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2634 | else if (rate > 24 * 2 && snr < 12) | 
|  | 2635 | rate = 27 * 2; | 
|  | 2636 | else if (rate > 24 * 2 && snr < 13) | 
|  | 2637 | rate = 30 * 2; | 
|  | 2638 | else if (rate > 24 * 2 && snr < 14) | 
|  | 2639 | rate = 33 * 2; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2640 | else if (rate > 36 * 2 && snr < 15) | 
|  | 2641 | rate = 36 * 2; | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2642 | else if (rate > 36 * 2 && snr < 16) | 
|  | 2643 | rate = 39 * 2; | 
|  | 2644 | else if (rate > 36 * 2 && snr < 17) | 
|  | 2645 | rate = 42 * 2; | 
|  | 2646 | else if (rate > 36 * 2 && snr < 18) | 
|  | 2647 | rate = 45 * 2; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2648 | else if (rate > 48 * 2 && snr < 19) | 
|  | 2649 | rate = 48 * 2; | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2650 | else if (rate > 48 * 2 && snr < 20) | 
|  | 2651 | rate = 51 * 2; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2652 | else if (rate > 54 * 2 && snr < 21) | 
|  | 2653 | rate = 54 * 2; | 
|  | 2654 | est = rate * 500; | 
|  | 2655 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2656 | hw_mode = get_mode_with_freq(wpa_s->hw.modes, wpa_s->hw.num_modes, | 
|  | 2657 | freq); | 
|  | 2658 |  | 
|  | 2659 | if (hw_mode && hw_mode->ht_capab) { | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2660 | ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2661 | if (ie) { | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2662 | tmp = max_ht20_rate(snr, false); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2663 | if (tmp > est) | 
|  | 2664 | est = tmp; | 
|  | 2665 | } | 
|  | 2666 | } | 
|  | 2667 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2668 | if (hw_mode && | 
|  | 2669 | (hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2670 | ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2671 | if (ie && ie[1] >= 2 && | 
|  | 2672 | (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2673 | tmp = max_ht40_rate(snr, false); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2674 | if (tmp > est) | 
|  | 2675 | est = tmp; | 
|  | 2676 | } | 
|  | 2677 | } | 
|  | 2678 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2679 | if (hw_mode && hw_mode->vht_capab) { | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2680 | /* Use +1 to assume VHT is always faster than HT */ | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2681 | ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2682 | if (ie) { | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2683 | bool vht80 = false, vht160 = false; | 
|  | 2684 |  | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2685 | tmp = max_ht20_rate(snr, true) + 1; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2686 | if (tmp > est) | 
|  | 2687 | est = tmp; | 
|  | 2688 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2689 | ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2690 | if (ie && ie[1] >= 2 && | 
|  | 2691 | (ie[3] & | 
|  | 2692 | HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { | 
| Hai Shalom | 899fcc7 | 2020-10-19 14:38:18 -0700 | [diff] [blame] | 2693 | tmp = max_ht40_rate(snr, true) + 1; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2694 | if (tmp > est) | 
|  | 2695 | est = tmp; | 
|  | 2696 | } | 
|  | 2697 |  | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2698 | /* Determine VHT BSS bandwidth based on IEEE Std | 
|  | 2699 | * 802.11-2020, Table 11-23 (VHT BSs bandwidth) */ | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2700 | ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2701 | if (ie && ie[1] >= 3) { | 
|  | 2702 | u8 cw = ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK; | 
|  | 2703 | u8 seg0 = ie[3]; | 
|  | 2704 | u8 seg1 = ie[4]; | 
|  | 2705 |  | 
|  | 2706 | if (cw) | 
|  | 2707 | vht80 = true; | 
|  | 2708 | if (cw == 2 || | 
|  | 2709 | (cw == 3 && | 
|  | 2710 | (seg1 > 0 && abs(seg1 - seg0) == 16))) | 
|  | 2711 | vht160 = true; | 
|  | 2712 | if (cw == 1 && | 
|  | 2713 | ((seg1 > 0 && abs(seg1 - seg0) == 8) || | 
|  | 2714 | (seg1 > 0 && abs(seg1 - seg0) == 16))) | 
|  | 2715 | vht160 = true; | 
|  | 2716 | } | 
|  | 2717 |  | 
|  | 2718 | if (vht80) { | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2719 | tmp = max_vht80_rate(snr) + 1; | 
|  | 2720 | if (tmp > est) | 
|  | 2721 | est = tmp; | 
|  | 2722 | } | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2723 |  | 
|  | 2724 | if (vht160 && | 
|  | 2725 | (hw_mode->vht_capab & | 
|  | 2726 | (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | | 
|  | 2727 | VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { | 
|  | 2728 | tmp = max_vht160_rate(snr) + 1; | 
|  | 2729 | if (tmp > est) | 
|  | 2730 | est = tmp; | 
|  | 2731 | } | 
|  | 2732 | } | 
|  | 2733 | } | 
|  | 2734 |  | 
|  | 2735 | if (hw_mode && hw_mode->he_capab[IEEE80211_MODE_INFRA].he_supported) { | 
|  | 2736 | /* Use +2 to assume HE is always faster than HT/VHT */ | 
|  | 2737 | struct ieee80211_he_capabilities *he; | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2738 | struct ieee80211_eht_capabilities *eht; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2739 | struct he_capabilities *own_he; | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2740 | u8 cw, boost = 2; | 
|  | 2741 | const u8 *eht_ie; | 
|  | 2742 | bool is_eht = false; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2743 |  | 
|  | 2744 | ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES); | 
|  | 2745 | if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN)) | 
|  | 2746 | return est; | 
|  | 2747 | he = (struct ieee80211_he_capabilities *) &ie[3]; | 
|  | 2748 | own_he = &hw_mode->he_capab[IEEE80211_MODE_INFRA]; | 
|  | 2749 |  | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2750 | /* Use +3 to assume EHT is always faster than HE */ | 
|  | 2751 | if (hw_mode->eht_capab[IEEE80211_MODE_INFRA].eht_supported) { | 
|  | 2752 | eht_ie = get_ie_ext(ies, ies_len, | 
|  | 2753 | WLAN_EID_EXT_EHT_CAPABILITIES); | 
|  | 2754 | if (eht_ie && | 
|  | 2755 | (eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN)) { | 
|  | 2756 | is_eht = true; | 
|  | 2757 | boost = 3; | 
|  | 2758 | } | 
|  | 2759 | } | 
|  | 2760 |  | 
|  | 2761 | tmp = max_he_eht_rate(he20_table, snr, is_eht) + boost; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2762 | if (tmp > est) | 
|  | 2763 | est = tmp; | 
|  | 2764 |  | 
|  | 2765 | cw = he->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & | 
|  | 2766 | own_he->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX]; | 
|  | 2767 | if (cw & | 
|  | 2768 | (IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G : | 
|  | 2769 | HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2770 | tmp = max_he_eht_rate(he40_table, snr, is_eht) + boost; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2771 | if (tmp > est) | 
|  | 2772 | est = tmp; | 
|  | 2773 | } | 
|  | 2774 |  | 
|  | 2775 | if (!IS_2P4GHZ(freq) && | 
|  | 2776 | (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2777 | tmp = max_he_eht_rate(he80_table, snr, is_eht) + boost; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2778 | if (tmp > est) | 
|  | 2779 | est = tmp; | 
|  | 2780 | } | 
|  | 2781 |  | 
|  | 2782 | if (!IS_2P4GHZ(freq) && | 
|  | 2783 | (cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | | 
|  | 2784 | HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) { | 
| Sunil Ravi | 38ad1ed | 2023-01-17 23:58:31 +0000 | [diff] [blame] | 2785 | tmp = max_he_eht_rate(he160_table, snr, is_eht) + boost; | 
|  | 2786 | if (tmp > est) | 
|  | 2787 | est = tmp; | 
|  | 2788 | } | 
|  | 2789 |  | 
|  | 2790 | if (!is_eht) | 
|  | 2791 | return est; | 
|  | 2792 |  | 
|  | 2793 | eht = (struct ieee80211_eht_capabilities *) &eht_ie[3]; | 
|  | 2794 |  | 
|  | 2795 | if (is_6ghz_freq(freq) && | 
|  | 2796 | (eht->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & | 
|  | 2797 | EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) { | 
|  | 2798 | tmp = max_he_eht_rate(eht320_table, snr, true); | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2799 | if (tmp > est) | 
|  | 2800 | est = tmp; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2801 | } | 
|  | 2802 | } | 
|  | 2803 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2804 | return est; | 
|  | 2805 | } | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2806 |  | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2807 |  | 
|  | 2808 | void scan_est_throughput(struct wpa_supplicant *wpa_s, | 
|  | 2809 | struct wpa_scan_res *res) | 
|  | 2810 | { | 
|  | 2811 | int rate; /* max legacy rate in 500 kb/s units */ | 
|  | 2812 | int snr = res->snr; | 
|  | 2813 | const u8 *ies = (const void *) (res + 1); | 
|  | 2814 | size_t ie_len = res->ie_len; | 
|  | 2815 |  | 
|  | 2816 | if (res->est_throughput) | 
|  | 2817 | return; | 
|  | 2818 |  | 
|  | 2819 | /* Get maximum legacy rate */ | 
|  | 2820 | rate = wpa_scan_get_max_rate(res); | 
|  | 2821 |  | 
|  | 2822 | if (!ie_len) | 
|  | 2823 | ie_len = res->beacon_ie_len; | 
|  | 2824 | res->est_throughput = | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 2825 | wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, res->freq); | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 2826 |  | 
|  | 2827 | /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2828 | } | 
|  | 2829 |  | 
|  | 2830 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2831 | /** | 
|  | 2832 | * wpa_supplicant_get_scan_results - Get scan results | 
|  | 2833 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 2834 | * @info: Information about what was scanned or %NULL if not available | 
|  | 2835 | * @new_scan: Whether a new scan was performed | 
|  | 2836 | * Returns: Scan results, %NULL on failure | 
|  | 2837 | * | 
|  | 2838 | * This function request the current scan results from the driver and updates | 
|  | 2839 | * the local BSS list wpa_s->bss. The caller is responsible for freeing the | 
|  | 2840 | * results with wpa_scan_results_free(). | 
|  | 2841 | */ | 
|  | 2842 | struct wpa_scan_results * | 
|  | 2843 | wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, | 
|  | 2844 | struct scan_info *info, int new_scan) | 
|  | 2845 | { | 
|  | 2846 | struct wpa_scan_results *scan_res; | 
|  | 2847 | size_t i; | 
|  | 2848 | int (*compar)(const void *, const void *) = wpa_scan_result_compar; | 
|  | 2849 |  | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2850 | scan_res = wpa_drv_get_scan_results2(wpa_s); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2851 | if (scan_res == NULL) { | 
|  | 2852 | wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); | 
|  | 2853 | return NULL; | 
|  | 2854 | } | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 2855 | if (scan_res->fetch_time.sec == 0) { | 
|  | 2856 | /* | 
|  | 2857 | * Make sure we have a valid timestamp if the driver wrapper | 
|  | 2858 | * does not set this. | 
|  | 2859 | */ | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2860 | os_get_reltime(&scan_res->fetch_time); | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 2861 | } | 
| Dmitry Shmidt | 0494959 | 2012-07-19 12:16:46 -0700 | [diff] [blame] | 2862 | filter_scan_res(wpa_s, scan_res); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2863 |  | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2864 | for (i = 0; i < scan_res->num; i++) { | 
|  | 2865 | struct wpa_scan_res *scan_res_item = scan_res->res[i]; | 
|  | 2866 |  | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 2867 | scan_snr(scan_res_item); | 
|  | 2868 | scan_est_throughput(wpa_s, scan_res_item); | 
| Dmitry Shmidt | 216983b | 2015-02-06 10:50:36 -0800 | [diff] [blame] | 2869 | } | 
|  | 2870 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2871 | #ifdef CONFIG_WPS | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2872 | if (wpas_wps_searching(wpa_s)) { | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2873 | wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS " | 
|  | 2874 | "provisioning rules"); | 
|  | 2875 | compar = wpa_scan_result_wps_compar; | 
|  | 2876 | } | 
|  | 2877 | #endif /* CONFIG_WPS */ | 
|  | 2878 |  | 
| Dmitry Shmidt | 9839ecd | 2016-11-07 11:05:47 -0800 | [diff] [blame] | 2879 | if (scan_res->res) { | 
|  | 2880 | qsort(scan_res->res, scan_res->num, | 
|  | 2881 | sizeof(struct wpa_scan_res *), compar); | 
|  | 2882 | } | 
| Dmitry Shmidt | 1f69aa5 | 2012-01-24 16:10:04 -0800 | [diff] [blame] | 2883 | dump_scan_res(scan_res); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2884 |  | 
| Dmitry Shmidt | 2933359 | 2017-01-09 12:27:11 -0800 | [diff] [blame] | 2885 | if (wpa_s->ignore_post_flush_scan_res) { | 
|  | 2886 | /* FLUSH command aborted an ongoing scan and these are the | 
|  | 2887 | * results from the aborted scan. Do not process the results to | 
|  | 2888 | * maintain flushed state. */ | 
|  | 2889 | wpa_dbg(wpa_s, MSG_DEBUG, | 
|  | 2890 | "Do not update BSS table based on pending post-FLUSH scan results"); | 
|  | 2891 | wpa_s->ignore_post_flush_scan_res = 0; | 
|  | 2892 | return scan_res; | 
|  | 2893 | } | 
|  | 2894 |  | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2895 | wpa_bss_update_start(wpa_s); | 
|  | 2896 | for (i = 0; i < scan_res->num; i++) | 
| Dmitry Shmidt | f862328 | 2013-02-20 14:34:59 -0800 | [diff] [blame] | 2897 | wpa_bss_update_scan_res(wpa_s, scan_res->res[i], | 
|  | 2898 | &scan_res->fetch_time); | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2899 | wpa_bss_update_end(wpa_s, info, new_scan); | 
|  | 2900 |  | 
|  | 2901 | return scan_res; | 
|  | 2902 | } | 
|  | 2903 |  | 
|  | 2904 |  | 
| Dmitry Shmidt | a54fa5f | 2013-01-15 13:53:35 -0800 | [diff] [blame] | 2905 | /** | 
|  | 2906 | * wpa_supplicant_update_scan_results - Update scan results from the driver | 
|  | 2907 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 2908 | * Returns: 0 on success, -1 on failure | 
|  | 2909 | * | 
|  | 2910 | * This function updates the BSS table within wpa_supplicant based on the | 
|  | 2911 | * currently available scan results from the driver without requesting a new | 
|  | 2912 | * scan. This is used in cases where the driver indicates an association | 
|  | 2913 | * (including roaming within ESS) and wpa_supplicant does not yet have the | 
|  | 2914 | * needed information to complete the connection (e.g., to perform validation | 
|  | 2915 | * steps in 4-way handshake). | 
|  | 2916 | */ | 
| Dmitry Shmidt | 8d520ff | 2011-05-09 14:06:53 -0700 | [diff] [blame] | 2917 | int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) | 
|  | 2918 | { | 
|  | 2919 | struct wpa_scan_results *scan_res; | 
|  | 2920 | scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); | 
|  | 2921 | if (scan_res == NULL) | 
|  | 2922 | return -1; | 
|  | 2923 | wpa_scan_results_free(scan_res); | 
|  | 2924 |  | 
|  | 2925 | return 0; | 
|  | 2926 | } | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 2927 |  | 
|  | 2928 |  | 
|  | 2929 | /** | 
|  | 2930 | * scan_only_handler - Reports scan results | 
|  | 2931 | */ | 
|  | 2932 | void scan_only_handler(struct wpa_supplicant *wpa_s, | 
|  | 2933 | struct wpa_scan_results *scan_res) | 
|  | 2934 | { | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 2935 | wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received"); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2936 | if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && | 
|  | 2937 | wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { | 
|  | 2938 | wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", | 
|  | 2939 | wpa_s->manual_scan_id); | 
|  | 2940 | wpa_s->manual_scan_use_id = 0; | 
|  | 2941 | } else { | 
|  | 2942 | wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); | 
|  | 2943 | } | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 2944 | wpas_notify_scan_results(wpa_s); | 
| Dmitry Shmidt | 4b9d52f | 2013-02-05 17:44:43 -0800 | [diff] [blame] | 2945 | wpas_notify_scan_done(wpa_s, 1); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2946 | if (wpa_s->scan_work) { | 
|  | 2947 | struct wpa_radio_work *work = wpa_s->scan_work; | 
|  | 2948 | wpa_s->scan_work = NULL; | 
|  | 2949 | radio_work_done(work); | 
|  | 2950 | } | 
| Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 2951 |  | 
|  | 2952 | if (wpa_s->wpa_state == WPA_SCANNING) | 
|  | 2953 | wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state); | 
| Dmitry Shmidt | 3a787e6 | 2013-01-17 10:32:35 -0800 | [diff] [blame] | 2954 | } | 
| Dmitry Shmidt | 37d4d6a | 2013-03-18 13:09:42 -0700 | [diff] [blame] | 2955 |  | 
|  | 2956 |  | 
|  | 2957 | int wpas_scan_scheduled(struct wpa_supplicant *wpa_s) | 
|  | 2958 | { | 
|  | 2959 | return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL); | 
|  | 2960 | } | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2961 |  | 
|  | 2962 |  | 
|  | 2963 | struct wpa_driver_scan_params * | 
|  | 2964 | wpa_scan_clone_params(const struct wpa_driver_scan_params *src) | 
|  | 2965 | { | 
|  | 2966 | struct wpa_driver_scan_params *params; | 
|  | 2967 | size_t i; | 
|  | 2968 | u8 *n; | 
|  | 2969 |  | 
|  | 2970 | params = os_zalloc(sizeof(*params)); | 
|  | 2971 | if (params == NULL) | 
|  | 2972 | return NULL; | 
|  | 2973 |  | 
|  | 2974 | for (i = 0; i < src->num_ssids; i++) { | 
|  | 2975 | if (src->ssids[i].ssid) { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 2976 | n = os_memdup(src->ssids[i].ssid, | 
|  | 2977 | src->ssids[i].ssid_len); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2978 | if (n == NULL) | 
|  | 2979 | goto failed; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2980 | params->ssids[i].ssid = n; | 
|  | 2981 | params->ssids[i].ssid_len = src->ssids[i].ssid_len; | 
|  | 2982 | } | 
|  | 2983 | } | 
|  | 2984 | params->num_ssids = src->num_ssids; | 
|  | 2985 |  | 
|  | 2986 | if (src->extra_ies) { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 2987 | n = os_memdup(src->extra_ies, src->extra_ies_len); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2988 | if (n == NULL) | 
|  | 2989 | goto failed; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2990 | params->extra_ies = n; | 
|  | 2991 | params->extra_ies_len = src->extra_ies_len; | 
|  | 2992 | } | 
|  | 2993 |  | 
|  | 2994 | if (src->freqs) { | 
|  | 2995 | int len = int_array_len(src->freqs); | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 2996 | params->freqs = os_memdup(src->freqs, (len + 1) * sizeof(int)); | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2997 | if (params->freqs == NULL) | 
|  | 2998 | goto failed; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 2999 | } | 
|  | 3000 |  | 
|  | 3001 | if (src->filter_ssids) { | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 3002 | params->filter_ssids = os_memdup(src->filter_ssids, | 
|  | 3003 | sizeof(*params->filter_ssids) * | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 3004 | src->num_filter_ssids); | 
|  | 3005 | if (params->filter_ssids == NULL) | 
|  | 3006 | goto failed; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 3007 | params->num_filter_ssids = src->num_filter_ssids; | 
|  | 3008 | } | 
|  | 3009 |  | 
|  | 3010 | params->filter_rssi = src->filter_rssi; | 
|  | 3011 | params->p2p_probe = src->p2p_probe; | 
|  | 3012 | params->only_new_results = src->only_new_results; | 
| Dmitry Shmidt | 2271d3f | 2014-06-23 12:16:31 -0700 | [diff] [blame] | 3013 | params->low_priority = src->low_priority; | 
| Dmitry Shmidt | 2933359 | 2017-01-09 12:27:11 -0800 | [diff] [blame] | 3014 | params->duration = src->duration; | 
|  | 3015 | params->duration_mandatory = src->duration_mandatory; | 
| Hai Shalom | ce48b4a | 2018-09-05 11:41:35 -0700 | [diff] [blame] | 3016 | params->oce_scan = src->oce_scan; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 3017 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3018 | if (src->sched_scan_plans_num > 0) { | 
|  | 3019 | params->sched_scan_plans = | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 3020 | os_memdup(src->sched_scan_plans, | 
|  | 3021 | sizeof(*src->sched_scan_plans) * | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3022 | src->sched_scan_plans_num); | 
|  | 3023 | if (!params->sched_scan_plans) | 
|  | 3024 | goto failed; | 
|  | 3025 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3026 | params->sched_scan_plans_num = src->sched_scan_plans_num; | 
|  | 3027 | } | 
|  | 3028 |  | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 3029 | if (src->mac_addr_rand && | 
|  | 3030 | wpa_setup_mac_addr_rand_params(params, src->mac_addr)) | 
|  | 3031 | goto failed; | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 3032 |  | 
|  | 3033 | if (src->bssid) { | 
|  | 3034 | u8 *bssid; | 
|  | 3035 |  | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 3036 | bssid = os_memdup(src->bssid, ETH_ALEN); | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 3037 | if (!bssid) | 
|  | 3038 | goto failed; | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 3039 | params->bssid = bssid; | 
|  | 3040 | } | 
|  | 3041 |  | 
| Dmitry Shmidt | ebd93af | 2017-02-21 13:40:44 -0800 | [diff] [blame] | 3042 | params->relative_rssi_set = src->relative_rssi_set; | 
|  | 3043 | params->relative_rssi = src->relative_rssi; | 
|  | 3044 | params->relative_adjust_band = src->relative_adjust_band; | 
|  | 3045 | params->relative_adjust_rssi = src->relative_adjust_rssi; | 
| Hai Shalom | a20dcd7 | 2022-02-04 13:43:00 -0800 | [diff] [blame] | 3046 | params->p2p_include_6ghz = src->p2p_include_6ghz; | 
| Sunil | 8cd6f4d | 2022-06-28 18:40:46 +0000 | [diff] [blame] | 3047 | params->non_coloc_6ghz = src->non_coloc_6ghz; | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 3048 | return params; | 
|  | 3049 |  | 
|  | 3050 | failed: | 
|  | 3051 | wpa_scan_free_params(params); | 
|  | 3052 | return NULL; | 
|  | 3053 | } | 
|  | 3054 |  | 
|  | 3055 |  | 
|  | 3056 | void wpa_scan_free_params(struct wpa_driver_scan_params *params) | 
|  | 3057 | { | 
|  | 3058 | size_t i; | 
|  | 3059 |  | 
|  | 3060 | if (params == NULL) | 
|  | 3061 | return; | 
|  | 3062 |  | 
|  | 3063 | for (i = 0; i < params->num_ssids; i++) | 
|  | 3064 | os_free((u8 *) params->ssids[i].ssid); | 
|  | 3065 | os_free((u8 *) params->extra_ies); | 
|  | 3066 | os_free(params->freqs); | 
|  | 3067 | os_free(params->filter_ssids); | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3068 | os_free(params->sched_scan_plans); | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 3069 |  | 
|  | 3070 | /* | 
|  | 3071 | * Note: params->mac_addr_mask points to same memory allocation and | 
|  | 3072 | * must not be freed separately. | 
|  | 3073 | */ | 
|  | 3074 | os_free((u8 *) params->mac_addr); | 
|  | 3075 |  | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 3076 | os_free((u8 *) params->bssid); | 
|  | 3077 |  | 
| Dmitry Shmidt | fb79edc | 2014-01-10 10:45:54 -0800 | [diff] [blame] | 3078 | os_free(params); | 
|  | 3079 | } | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3080 |  | 
|  | 3081 |  | 
|  | 3082 | int wpas_start_pno(struct wpa_supplicant *wpa_s) | 
|  | 3083 | { | 
| Hai Shalom | fdcde76 | 2020-04-02 11:19:20 -0700 | [diff] [blame] | 3084 | int ret; | 
|  | 3085 | size_t prio, i, num_ssid, num_match_ssid; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3086 | struct wpa_ssid *ssid; | 
|  | 3087 | struct wpa_driver_scan_params params; | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3088 | struct sched_scan_plan scan_plan; | 
| Dmitry Shmidt | e466304 | 2016-04-04 10:07:49 -0700 | [diff] [blame] | 3089 | unsigned int max_sched_scan_ssids; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3090 |  | 
|  | 3091 | if (!wpa_s->sched_scan_supported) | 
|  | 3092 | return -1; | 
|  | 3093 |  | 
| Dmitry Shmidt | e466304 | 2016-04-04 10:07:49 -0700 | [diff] [blame] | 3094 | if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) | 
|  | 3095 | max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; | 
|  | 3096 | else | 
|  | 3097 | max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; | 
|  | 3098 | if (max_sched_scan_ssids < 1) | 
|  | 3099 | return -1; | 
|  | 3100 |  | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3101 | if (wpa_s->pno || wpa_s->pno_sched_pending) | 
|  | 3102 | return 0; | 
|  | 3103 |  | 
|  | 3104 | if ((wpa_s->wpa_state > WPA_SCANNING) && | 
| Dmitry Shmidt | ebd93af | 2017-02-21 13:40:44 -0800 | [diff] [blame] | 3105 | (wpa_s->wpa_state < WPA_COMPLETED)) { | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3106 | wpa_printf(MSG_ERROR, "PNO: In assoc process"); | 
|  | 3107 | return -EAGAIN; | 
|  | 3108 | } | 
|  | 3109 |  | 
|  | 3110 | if (wpa_s->wpa_state == WPA_SCANNING) { | 
|  | 3111 | wpa_supplicant_cancel_scan(wpa_s); | 
|  | 3112 | if (wpa_s->sched_scanning) { | 
|  | 3113 | wpa_printf(MSG_DEBUG, "Schedule PNO on completion of " | 
|  | 3114 | "ongoing sched scan"); | 
|  | 3115 | wpa_supplicant_cancel_sched_scan(wpa_s); | 
|  | 3116 | wpa_s->pno_sched_pending = 1; | 
|  | 3117 | return 0; | 
|  | 3118 | } | 
|  | 3119 | } | 
|  | 3120 |  | 
| Dmitry Shmidt | 9839ecd | 2016-11-07 11:05:47 -0800 | [diff] [blame] | 3121 | if (wpa_s->sched_scan_stop_req) { | 
|  | 3122 | wpa_printf(MSG_DEBUG, | 
|  | 3123 | "Schedule PNO after previous sched scan has stopped"); | 
|  | 3124 | wpa_s->pno_sched_pending = 1; | 
|  | 3125 | return 0; | 
|  | 3126 | } | 
|  | 3127 |  | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3128 | os_memset(¶ms, 0, sizeof(params)); | 
|  | 3129 |  | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3130 | num_ssid = num_match_ssid = 0; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3131 | ssid = wpa_s->conf->ssid; | 
|  | 3132 | while (ssid) { | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3133 | if (!wpas_network_disabled(wpa_s, ssid)) { | 
|  | 3134 | num_match_ssid++; | 
|  | 3135 | if (ssid->scan_ssid) | 
|  | 3136 | num_ssid++; | 
|  | 3137 | } | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3138 | ssid = ssid->next; | 
|  | 3139 | } | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3140 |  | 
|  | 3141 | if (num_match_ssid == 0) { | 
|  | 3142 | wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs"); | 
|  | 3143 | return -1; | 
|  | 3144 | } | 
|  | 3145 |  | 
|  | 3146 | if (num_match_ssid > num_ssid) { | 
|  | 3147 | params.num_ssids++; /* wildcard */ | 
|  | 3148 | num_ssid++; | 
|  | 3149 | } | 
|  | 3150 |  | 
| Dmitry Shmidt | e466304 | 2016-04-04 10:07:49 -0700 | [diff] [blame] | 3151 | if (num_ssid > max_sched_scan_ssids) { | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3152 | wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from " | 
| Dmitry Shmidt | e466304 | 2016-04-04 10:07:49 -0700 | [diff] [blame] | 3153 | "%u", max_sched_scan_ssids, (unsigned int) num_ssid); | 
|  | 3154 | num_ssid = max_sched_scan_ssids; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3155 | } | 
|  | 3156 |  | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3157 | if (num_match_ssid > wpa_s->max_match_sets) { | 
|  | 3158 | num_match_ssid = wpa_s->max_match_sets; | 
|  | 3159 | wpa_dbg(wpa_s, MSG_DEBUG, "PNO: Too many SSIDs to match"); | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3160 | } | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3161 | params.filter_ssids = os_calloc(num_match_ssid, | 
|  | 3162 | sizeof(struct wpa_driver_scan_filter)); | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3163 | if (params.filter_ssids == NULL) | 
|  | 3164 | return -1; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 3165 |  | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3166 | i = 0; | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 3167 | prio = 0; | 
|  | 3168 | ssid = wpa_s->conf->pssid[prio]; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3169 | while (ssid) { | 
|  | 3170 | if (!wpas_network_disabled(wpa_s, ssid)) { | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3171 | if (ssid->scan_ssid && params.num_ssids < num_ssid) { | 
|  | 3172 | params.ssids[params.num_ssids].ssid = | 
|  | 3173 | ssid->ssid; | 
|  | 3174 | params.ssids[params.num_ssids].ssid_len = | 
|  | 3175 | ssid->ssid_len; | 
|  | 3176 | params.num_ssids++; | 
|  | 3177 | } | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3178 | os_memcpy(params.filter_ssids[i].ssid, ssid->ssid, | 
|  | 3179 | ssid->ssid_len); | 
|  | 3180 | params.filter_ssids[i].ssid_len = ssid->ssid_len; | 
|  | 3181 | params.num_filter_ssids++; | 
|  | 3182 | i++; | 
| Dmitry Shmidt | 6aa8ae4 | 2014-07-07 09:31:33 -0700 | [diff] [blame] | 3183 | if (i == num_match_ssid) | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3184 | break; | 
|  | 3185 | } | 
| Dmitry Shmidt | 7f65602 | 2015-02-25 14:36:37 -0800 | [diff] [blame] | 3186 | if (ssid->pnext) | 
|  | 3187 | ssid = ssid->pnext; | 
|  | 3188 | else if (prio + 1 == wpa_s->conf->num_prio) | 
|  | 3189 | break; | 
|  | 3190 | else | 
|  | 3191 | ssid = wpa_s->conf->pssid[++prio]; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3192 | } | 
|  | 3193 |  | 
|  | 3194 | if (wpa_s->conf->filter_rssi) | 
|  | 3195 | params.filter_rssi = wpa_s->conf->filter_rssi; | 
|  | 3196 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3197 | if (wpa_s->sched_scan_plans_num) { | 
|  | 3198 | params.sched_scan_plans = wpa_s->sched_scan_plans; | 
|  | 3199 | params.sched_scan_plans_num = wpa_s->sched_scan_plans_num; | 
|  | 3200 | } else { | 
|  | 3201 | /* Set one scan plan that will run infinitely */ | 
|  | 3202 | if (wpa_s->conf->sched_scan_interval) | 
|  | 3203 | scan_plan.interval = wpa_s->conf->sched_scan_interval; | 
|  | 3204 | else | 
|  | 3205 | scan_plan.interval = 10; | 
|  | 3206 |  | 
|  | 3207 | scan_plan.iterations = 0; | 
|  | 3208 | params.sched_scan_plans = &scan_plan; | 
|  | 3209 | params.sched_scan_plans_num = 1; | 
|  | 3210 | } | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3211 |  | 
| Dmitry Shmidt | d2986c2 | 2017-10-23 14:22:09 -0700 | [diff] [blame] | 3212 | params.sched_scan_start_delay = wpa_s->conf->sched_scan_start_delay; | 
|  | 3213 |  | 
| Dmitry Shmidt | d11f019 | 2014-03-24 12:09:47 -0700 | [diff] [blame] | 3214 | if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) { | 
|  | 3215 | wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels"); | 
|  | 3216 | params.freqs = wpa_s->manual_sched_scan_freqs; | 
|  | 3217 | } | 
|  | 3218 |  | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 3219 | if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) && | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 3220 | wpa_s->wpa_state <= WPA_SCANNING) | 
|  | 3221 | wpa_setup_mac_addr_rand_params(¶ms, wpa_s->mac_addr_pno); | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 3222 |  | 
| Dmitry Shmidt | ebd93af | 2017-02-21 13:40:44 -0800 | [diff] [blame] | 3223 | wpa_scan_set_relative_rssi_params(wpa_s, ¶ms); | 
|  | 3224 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3225 | ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms); | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3226 | os_free(params.filter_ssids); | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 3227 | os_free(params.mac_addr); | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3228 | if (ret == 0) | 
|  | 3229 | wpa_s->pno = 1; | 
|  | 3230 | else | 
|  | 3231 | wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO"); | 
|  | 3232 | return ret; | 
|  | 3233 | } | 
|  | 3234 |  | 
|  | 3235 |  | 
|  | 3236 | int wpas_stop_pno(struct wpa_supplicant *wpa_s) | 
|  | 3237 | { | 
|  | 3238 | int ret = 0; | 
|  | 3239 |  | 
|  | 3240 | if (!wpa_s->pno) | 
|  | 3241 | return 0; | 
|  | 3242 |  | 
|  | 3243 | ret = wpa_supplicant_stop_sched_scan(wpa_s); | 
| Dmitry Shmidt | 9839ecd | 2016-11-07 11:05:47 -0800 | [diff] [blame] | 3244 | wpa_s->sched_scan_stop_req = 1; | 
| Dmitry Shmidt | 9866086 | 2014-03-11 17:26:21 -0700 | [diff] [blame] | 3245 |  | 
|  | 3246 | wpa_s->pno = 0; | 
|  | 3247 | wpa_s->pno_sched_pending = 0; | 
|  | 3248 |  | 
|  | 3249 | if (wpa_s->wpa_state == WPA_SCANNING) | 
|  | 3250 | wpa_supplicant_req_scan(wpa_s, 0, 0); | 
|  | 3251 |  | 
|  | 3252 | return ret; | 
|  | 3253 | } | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 3254 |  | 
|  | 3255 |  | 
|  | 3256 | void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s, | 
|  | 3257 | unsigned int type) | 
|  | 3258 | { | 
|  | 3259 | type &= MAC_ADDR_RAND_ALL; | 
|  | 3260 | wpa_s->mac_addr_rand_enable &= ~type; | 
|  | 3261 |  | 
|  | 3262 | if (type & MAC_ADDR_RAND_SCAN) { | 
|  | 3263 | os_free(wpa_s->mac_addr_scan); | 
|  | 3264 | wpa_s->mac_addr_scan = NULL; | 
|  | 3265 | } | 
|  | 3266 |  | 
|  | 3267 | if (type & MAC_ADDR_RAND_SCHED_SCAN) { | 
|  | 3268 | os_free(wpa_s->mac_addr_sched_scan); | 
|  | 3269 | wpa_s->mac_addr_sched_scan = NULL; | 
|  | 3270 | } | 
|  | 3271 |  | 
|  | 3272 | if (type & MAC_ADDR_RAND_PNO) { | 
|  | 3273 | os_free(wpa_s->mac_addr_pno); | 
|  | 3274 | wpa_s->mac_addr_pno = NULL; | 
|  | 3275 | } | 
|  | 3276 | } | 
|  | 3277 |  | 
|  | 3278 |  | 
|  | 3279 | int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, | 
|  | 3280 | unsigned int type, const u8 *addr, | 
|  | 3281 | const u8 *mask) | 
|  | 3282 | { | 
|  | 3283 | u8 *tmp = NULL; | 
|  | 3284 |  | 
| Hai Shalom | 74f70d4 | 2019-02-11 14:42:39 -0800 | [diff] [blame] | 3285 | if ((wpa_s->mac_addr_rand_supported & type) != type ) { | 
|  | 3286 | wpa_printf(MSG_INFO, | 
|  | 3287 | "scan: MAC randomization type %u != supported=%u", | 
|  | 3288 | type, wpa_s->mac_addr_rand_supported); | 
|  | 3289 | return -1; | 
|  | 3290 | } | 
|  | 3291 |  | 
| Dmitry Shmidt | 6c0da2b | 2015-01-05 13:08:17 -0800 | [diff] [blame] | 3292 | wpas_mac_addr_rand_scan_clear(wpa_s, type); | 
|  | 3293 |  | 
|  | 3294 | if (addr) { | 
|  | 3295 | tmp = os_malloc(2 * ETH_ALEN); | 
|  | 3296 | if (!tmp) | 
|  | 3297 | return -1; | 
|  | 3298 | os_memcpy(tmp, addr, ETH_ALEN); | 
|  | 3299 | os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN); | 
|  | 3300 | } | 
|  | 3301 |  | 
|  | 3302 | if (type == MAC_ADDR_RAND_SCAN) { | 
|  | 3303 | wpa_s->mac_addr_scan = tmp; | 
|  | 3304 | } else if (type == MAC_ADDR_RAND_SCHED_SCAN) { | 
|  | 3305 | wpa_s->mac_addr_sched_scan = tmp; | 
|  | 3306 | } else if (type == MAC_ADDR_RAND_PNO) { | 
|  | 3307 | wpa_s->mac_addr_pno = tmp; | 
|  | 3308 | } else { | 
|  | 3309 | wpa_printf(MSG_INFO, | 
|  | 3310 | "scan: Invalid MAC randomization type=0x%x", | 
|  | 3311 | type); | 
|  | 3312 | os_free(tmp); | 
|  | 3313 | return -1; | 
|  | 3314 | } | 
|  | 3315 |  | 
|  | 3316 | wpa_s->mac_addr_rand_enable |= type; | 
|  | 3317 | return 0; | 
|  | 3318 | } | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3319 |  | 
|  | 3320 |  | 
| Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 3321 | int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s, | 
|  | 3322 | unsigned int type, u8 *mask) | 
|  | 3323 | { | 
|  | 3324 | const u8 *to_copy; | 
|  | 3325 |  | 
|  | 3326 | if ((wpa_s->mac_addr_rand_enable & type) != type) | 
|  | 3327 | return -1; | 
|  | 3328 |  | 
|  | 3329 | if (type == MAC_ADDR_RAND_SCAN) { | 
|  | 3330 | to_copy = wpa_s->mac_addr_scan; | 
|  | 3331 | } else if (type == MAC_ADDR_RAND_SCHED_SCAN) { | 
|  | 3332 | to_copy = wpa_s->mac_addr_sched_scan; | 
|  | 3333 | } else if (type == MAC_ADDR_RAND_PNO) { | 
|  | 3334 | to_copy = wpa_s->mac_addr_pno; | 
|  | 3335 | } else { | 
|  | 3336 | wpa_printf(MSG_DEBUG, | 
|  | 3337 | "scan: Invalid MAC randomization type=0x%x", | 
|  | 3338 | type); | 
|  | 3339 | return -1; | 
|  | 3340 | } | 
|  | 3341 |  | 
|  | 3342 | os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN); | 
|  | 3343 | return 0; | 
|  | 3344 | } | 
|  | 3345 |  | 
|  | 3346 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3347 | int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s) | 
|  | 3348 | { | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 3349 | struct wpa_radio_work *work; | 
|  | 3350 | struct wpa_radio *radio = wpa_s->radio; | 
| Dmitry Shmidt | 9c17526 | 2016-03-03 10:20:07 -0800 | [diff] [blame] | 3351 |  | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 3352 | dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) { | 
|  | 3353 | if (work->wpa_s != wpa_s || !work->started || | 
|  | 3354 | (os_strcmp(work->type, "scan") != 0 && | 
|  | 3355 | os_strcmp(work->type, "p2p-scan") != 0)) | 
|  | 3356 | continue; | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3357 | wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan"); | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 3358 | return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie); | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3359 | } | 
|  | 3360 |  | 
| Dmitry Shmidt | abb90a3 | 2016-12-05 15:34:39 -0800 | [diff] [blame] | 3361 | wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort"); | 
|  | 3362 | return -1; | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3363 | } | 
|  | 3364 |  | 
|  | 3365 |  | 
|  | 3366 | int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd) | 
|  | 3367 | { | 
|  | 3368 | struct sched_scan_plan *scan_plans = NULL; | 
|  | 3369 | const char *token, *context = NULL; | 
|  | 3370 | unsigned int num = 0; | 
|  | 3371 |  | 
|  | 3372 | if (!cmd) | 
|  | 3373 | return -1; | 
|  | 3374 |  | 
|  | 3375 | if (!cmd[0]) { | 
|  | 3376 | wpa_printf(MSG_DEBUG, "Clear sched scan plans"); | 
|  | 3377 | os_free(wpa_s->sched_scan_plans); | 
|  | 3378 | wpa_s->sched_scan_plans = NULL; | 
|  | 3379 | wpa_s->sched_scan_plans_num = 0; | 
|  | 3380 | return 0; | 
|  | 3381 | } | 
|  | 3382 |  | 
|  | 3383 | while ((token = cstr_token(cmd, " ", &context))) { | 
|  | 3384 | int ret; | 
|  | 3385 | struct sched_scan_plan *scan_plan, *n; | 
|  | 3386 |  | 
|  | 3387 | n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans)); | 
|  | 3388 | if (!n) | 
|  | 3389 | goto fail; | 
|  | 3390 |  | 
|  | 3391 | scan_plans = n; | 
|  | 3392 | scan_plan = &scan_plans[num]; | 
|  | 3393 | num++; | 
|  | 3394 |  | 
|  | 3395 | ret = sscanf(token, "%u:%u", &scan_plan->interval, | 
|  | 3396 | &scan_plan->iterations); | 
|  | 3397 | if (ret <= 0 || ret > 2 || !scan_plan->interval) { | 
|  | 3398 | wpa_printf(MSG_ERROR, | 
|  | 3399 | "Invalid sched scan plan input: %s", token); | 
|  | 3400 | goto fail; | 
|  | 3401 | } | 
|  | 3402 |  | 
| Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 3403 | if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) { | 
|  | 3404 | wpa_printf(MSG_WARNING, | 
|  | 3405 | "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)", | 
|  | 3406 | num, scan_plan->interval, | 
|  | 3407 | wpa_s->max_sched_scan_plan_interval); | 
|  | 3408 | scan_plan->interval = | 
|  | 3409 | wpa_s->max_sched_scan_plan_interval; | 
|  | 3410 | } | 
|  | 3411 |  | 
|  | 3412 | if (ret == 1) { | 
|  | 3413 | scan_plan->iterations = 0; | 
|  | 3414 | break; | 
|  | 3415 | } | 
|  | 3416 |  | 
|  | 3417 | if (!scan_plan->iterations) { | 
|  | 3418 | wpa_printf(MSG_ERROR, | 
|  | 3419 | "scan plan %u: Number of iterations cannot be zero", | 
|  | 3420 | num); | 
|  | 3421 | goto fail; | 
|  | 3422 | } | 
|  | 3423 |  | 
|  | 3424 | if (scan_plan->iterations > | 
|  | 3425 | wpa_s->max_sched_scan_plan_iterations) { | 
|  | 3426 | wpa_printf(MSG_WARNING, | 
|  | 3427 | "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)", | 
|  | 3428 | num, scan_plan->iterations, | 
|  | 3429 | wpa_s->max_sched_scan_plan_iterations); | 
|  | 3430 | scan_plan->iterations = | 
|  | 3431 | wpa_s->max_sched_scan_plan_iterations; | 
|  | 3432 | } | 
|  | 3433 |  | 
|  | 3434 | wpa_printf(MSG_DEBUG, | 
|  | 3435 | "scan plan %u: interval=%u iterations=%u", | 
|  | 3436 | num, scan_plan->interval, scan_plan->iterations); | 
|  | 3437 | } | 
|  | 3438 |  | 
|  | 3439 | if (!scan_plans) { | 
|  | 3440 | wpa_printf(MSG_ERROR, "Invalid scan plans entry"); | 
|  | 3441 | goto fail; | 
|  | 3442 | } | 
|  | 3443 |  | 
|  | 3444 | if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) { | 
|  | 3445 | wpa_printf(MSG_ERROR, | 
|  | 3446 | "All scan plans but the last must specify a number of iterations"); | 
|  | 3447 | goto fail; | 
|  | 3448 | } | 
|  | 3449 |  | 
|  | 3450 | wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u", | 
|  | 3451 | num, scan_plans[num - 1].interval); | 
|  | 3452 |  | 
|  | 3453 | if (num > wpa_s->max_sched_scan_plans) { | 
|  | 3454 | wpa_printf(MSG_WARNING, | 
|  | 3455 | "Too many scheduled scan plans (only %u supported)", | 
|  | 3456 | wpa_s->max_sched_scan_plans); | 
|  | 3457 | wpa_printf(MSG_WARNING, | 
|  | 3458 | "Use only the first %u scan plans, and the last one (in infinite loop)", | 
|  | 3459 | wpa_s->max_sched_scan_plans - 1); | 
|  | 3460 | os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1], | 
|  | 3461 | &scan_plans[num - 1], sizeof(*scan_plans)); | 
|  | 3462 | num = wpa_s->max_sched_scan_plans; | 
|  | 3463 | } | 
|  | 3464 |  | 
|  | 3465 | os_free(wpa_s->sched_scan_plans); | 
|  | 3466 | wpa_s->sched_scan_plans = scan_plans; | 
|  | 3467 | wpa_s->sched_scan_plans_num = num; | 
|  | 3468 |  | 
|  | 3469 | return 0; | 
|  | 3470 |  | 
|  | 3471 | fail: | 
|  | 3472 | os_free(scan_plans); | 
|  | 3473 | wpa_printf(MSG_ERROR, "invalid scan plans list"); | 
|  | 3474 | return -1; | 
|  | 3475 | } | 
| Dmitry Shmidt | aca489e | 2016-09-28 15:44:14 -0700 | [diff] [blame] | 3476 |  | 
|  | 3477 |  | 
|  | 3478 | /** | 
|  | 3479 | * wpas_scan_reset_sched_scan - Reset sched_scan state | 
|  | 3480 | * @wpa_s: Pointer to wpa_supplicant data | 
|  | 3481 | * | 
|  | 3482 | * This function is used to cancel a running scheduled scan and to reset an | 
|  | 3483 | * internal scan state to continue with a regular scan on the following | 
|  | 3484 | * wpa_supplicant_req_scan() calls. | 
|  | 3485 | */ | 
|  | 3486 | void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s) | 
|  | 3487 | { | 
|  | 3488 | wpa_s->normal_scans = 0; | 
|  | 3489 | if (wpa_s->sched_scanning) { | 
|  | 3490 | wpa_s->sched_scan_timed_out = 0; | 
|  | 3491 | wpa_s->prev_sched_ssid = NULL; | 
|  | 3492 | wpa_supplicant_cancel_sched_scan(wpa_s); | 
|  | 3493 | } | 
|  | 3494 | } | 
|  | 3495 |  | 
|  | 3496 |  | 
|  | 3497 | void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s) | 
|  | 3498 | { | 
|  | 3499 | /* simulate timeout to restart the sched scan */ | 
|  | 3500 | wpa_s->sched_scan_timed_out = 1; | 
|  | 3501 | wpa_s->prev_sched_ssid = NULL; | 
|  | 3502 | wpa_supplicant_cancel_sched_scan(wpa_s); | 
|  | 3503 | } |