/** * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan * @wpa_s: Pointer to wpa_supplicant data * * This function is used to schedule periodic scans for neighboring * access points repeating the scan continuously. */ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) { struct wpa_driver_scan_params params; enum wpa_states prev_state; struct wpa_ssid *ssid = NULL; struct wpabuf *extra_ie = NULL; int ret; unsigned int max_sched_scan_ssids; if (!wpa_s->sched_scan_supported) return -1; if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; else max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; if (wpa_s->sched_scanning) return 0; os_memset(¶ms, 0, sizeof(params)); /* If we can't allocate space for the filters, we just don't filter */ params.filter_ssids = os_zalloc(wpa_s->max_match_sets * sizeof(struct wpa_driver_scan_filter)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_sched_ssid) { while (ssid) { if (ssid == wpa_s->prev_sched_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (!ssid || !wpa_s->prev_sched_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); wpa_s->sched_scan_interval = 2; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; wpa_s->first_sched_scan = 1; ssid = wpa_s->conf->ssid; wpa_s->prev_sched_ssid = ssid; } while (ssid) { if (ssid->disabled) { wpa_s->prev_sched_ssid = ssid; ssid = ssid->next; continue; } if (params.filter_ssids && ssid->ssid && ssid->ssid_len) { os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid, ssid->ssid, ssid->ssid_len); params.filter_ssids[params.num_filter_ssids].ssid_len = ssid->ssid_len; params.num_filter_ssids++; } if (ssid->scan_ssid) { params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids >= max_sched_scan_ssids) { wpa_s->prev_sched_ssid = ssid; break; } } if (params.num_filter_ssids >= wpa_s->max_match_sets) break; wpa_s->prev_sched_ssid = ssid; ssid = ssid->next; } if (!params.num_ssids) { os_free(params.filter_ssids); return 0; } extra_ie = wpa_supplicant_extra_ies(wpa_s); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d timeout %d", wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, wpa_s->sched_scan_interval); wpabuf_free(extra_ie); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); return ret; } /* If we have more SSIDs to scan, add a timeout so we scan them too */ if (ssid || !wpa_s->first_sched_scan) { wpa_s->sched_scan_timed_out = 0; eloop_register_timeout(wpa_s->sched_scan_timeout, 0, wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_s->first_sched_scan = 0; wpa_s->sched_scan_timeout /= 2; wpa_s->sched_scan_interval *= 2; } return 0; }
/** * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan * @wpa_s: Pointer to wpa_supplicant data * * This function is used to schedule periodic scans for neighboring * access points repeating the scan continuously. */ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) { struct wpa_driver_scan_params params; enum wpa_states prev_state; struct wpa_ssid *ssid; struct wpabuf *wps_ie = NULL; int ret; unsigned int max_sched_scan_ssids; int wildcard = 0; int need_ssids; if (!wpa_s->sched_scan_supported) return -1; if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; else max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; if (max_sched_scan_ssids < 1) return -1; if (wpa_s->sched_scanning) { wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); return 0; } need_ssids = 0; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!ssid->disabled && !ssid->scan_ssid) { /* Use wildcard SSID to find this network */ wildcard = 1; } else if (!ssid->disabled && ssid->ssid_len) need_ssids++; } if (wildcard) need_ssids++; if (wpa_s->normal_scans < 3 && (need_ssids <= wpa_s->max_scan_ssids || wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) { /* * When normal scan can speed up operations, use that for the * first operations before starting the sched_scan to allow * user space sleep more. We do this only if the normal scan * has functionality that is suitable for this or if the * sched_scan does not have better support for multiple SSIDs. */ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " "sched_scan for initial scans (normal_scans=%d)", wpa_s->normal_scans); return -1; } os_memset(¶ms, 0, sizeof(params)); /* If we can't allocate space for the filters, we just don't filter */ params.filter_ssids = os_zalloc(wpa_s->max_match_sets * sizeof(struct wpa_driver_scan_filter)); prev_state = wpa_s->wpa_state; #ifndef ANDROID_P2P if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); #endif /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_sched_ssid) { while (ssid) { if (ssid == wpa_s->prev_sched_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (!ssid || !wpa_s->prev_sched_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; wpa_s->first_sched_scan = 1; ssid = wpa_s->conf->ssid; wpa_s->prev_sched_ssid = ssid; } if (wildcard) { wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan"); params.num_ssids++; } while (ssid) { if (ssid->disabled) goto next; if (params.num_filter_ssids < wpa_s->max_match_sets && params.filter_ssids && ssid->ssid && ssid->ssid_len) { wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid, ssid->ssid, ssid->ssid_len); params.filter_ssids[params.num_filter_ssids].ssid_len = ssid->ssid_len; params.num_filter_ssids++; } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len) { wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID " "filter for sched_scan - drop filter"); os_free(params.filter_ssids); params.filter_ssids = NULL; params.num_filter_ssids = 0; } if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) { if (params.num_ssids == max_sched_scan_ssids) break; /* only room for broadcast SSID */ wpa_dbg(wpa_s, MSG_DEBUG, "add to active scan ssid: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids >= max_sched_scan_ssids) { wpa_s->prev_sched_ssid = ssid; break; } } next: wpa_s->prev_sched_ssid = ssid; ssid = ssid->next; } if (params.num_filter_ssids == 0) { os_free(params.filter_ssids); params.filter_ssids = NULL; } if (wpa_s->wps) wps_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); if (ssid || !wpa_s->first_sched_scan) { wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d (no timeout)", wpa_s->sched_scan_interval); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d timeout %d", wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); } ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, wpa_s->sched_scan_interval); wpabuf_free(wps_ie); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); return ret; } /* If we have more SSIDs to scan, add a timeout so we scan them too */ if (ssid || !wpa_s->first_sched_scan) { wpa_s->sched_scan_timed_out = 0; eloop_register_timeout(wpa_s->sched_scan_timeout, 0, wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_s->first_sched_scan = 0; wpa_s->sched_scan_timeout /= 2; wpa_s->sched_scan_interval *= 2; } return 0; }
/** * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 is sched_scan was started or -1 otherwise * * This function is used to schedule periodic scans for neighboring * access points repeating the scan continuously. */ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) { struct wpa_driver_scan_params params; struct wpa_driver_scan_params *scan_params; enum wpa_states prev_state; struct wpa_ssid *ssid = NULL; struct wpabuf *extra_ie = NULL; int ret; unsigned int max_sched_scan_ssids; int wildcard = 0; int need_ssids; if (!wpa_s->sched_scan_supported) return -1; if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; else max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload) return -1; if (wpa_s->sched_scanning) { wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); return 0; } need_ssids = 0; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) { /* Use wildcard SSID to find this network */ wildcard = 1; } else if (!wpas_network_disabled(wpa_s, ssid) && ssid->ssid_len) need_ssids++; #ifdef CONFIG_WPS if (!wpas_network_disabled(wpa_s, ssid) && ssid->key_mgmt == WPA_KEY_MGMT_WPS) { /* * Normal scan is more reliable and faster for WPS * operations and since these are for short periods of * time, the benefit of trying to use sched_scan would * be limited. */ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " "sched_scan for WPS"); return -1; } #endif /* CONFIG_WPS */ } if (wildcard) need_ssids++; if (wpa_s->normal_scans < 3 && (need_ssids <= wpa_s->max_scan_ssids || wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) { /* * When normal scan can speed up operations, use that for the * first operations before starting the sched_scan to allow * user space sleep more. We do this only if the normal scan * has functionality that is suitable for this or if the * sched_scan does not have better support for multiple SSIDs. */ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " "sched_scan for initial scans (normal_scans=%d)", wpa_s->normal_scans); return -1; } os_memset(¶ms, 0, sizeof(params)); /* If we can't allocate space for the filters, we just don't filter */ params.filter_ssids = os_zalloc(wpa_s->max_match_sets * sizeof(struct wpa_driver_scan_filter)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); if (wpa_s->autoscan_params != NULL) { scan_params = wpa_s->autoscan_params; goto scan; } /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_sched_ssid) { while (ssid) { if (ssid == wpa_s->prev_sched_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (!ssid || !wpa_s->prev_sched_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); if (wpa_s->conf->sched_scan_interval) wpa_s->sched_scan_interval = wpa_s->conf->sched_scan_interval; if (wpa_s->sched_scan_interval == 0) wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; wpa_s->first_sched_scan = 1; ssid = wpa_s->conf->ssid; wpa_s->prev_sched_ssid = ssid; } if (wildcard) { wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan"); params.num_ssids++; } while (ssid) { if (wpas_network_disabled(wpa_s, ssid)) goto next; if (params.num_filter_ssids < wpa_s->max_match_sets && params.filter_ssids && ssid->ssid && ssid->ssid_len) { wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid, ssid->ssid, ssid->ssid_len); params.filter_ssids[params.num_filter_ssids].ssid_len = ssid->ssid_len; params.num_filter_ssids++; } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len) { wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID " "filter for sched_scan - drop filter"); os_free(params.filter_ssids); params.filter_ssids = NULL; params.num_filter_ssids = 0; } if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) { if (params.num_ssids == max_sched_scan_ssids) break; /* only room for broadcast SSID */ wpa_dbg(wpa_s, MSG_DEBUG, "add to active scan ssid: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids >= max_sched_scan_ssids) { wpa_s->prev_sched_ssid = ssid; do { ssid = ssid->next; } while (ssid && (wpas_network_disabled(wpa_s, ssid) || !ssid->scan_ssid)); break; } } next: wpa_s->prev_sched_ssid = ssid; ssid = ssid->next; } if (params.num_filter_ssids == 0) { os_free(params.filter_ssids); params.filter_ssids = NULL; } extra_ie = wpa_supplicant_extra_ies(wpa_s); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } if (wpa_s->conf->filter_rssi) params.filter_rssi = wpa_s->conf->filter_rssi; scan_params = ¶ms; scan: if (ssid || !wpa_s->first_sched_scan) { wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d timeout %d", wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d (no timeout)", wpa_s->sched_scan_interval); } wpa_setband_scan_freqs(wpa_s, scan_params); ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params, wpa_s->sched_scan_interval); wpabuf_free(extra_ie); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); return ret; } /* If we have more SSIDs to scan, add a timeout so we scan them too */ if (ssid || !wpa_s->first_sched_scan) { wpa_s->sched_scan_timed_out = 0; eloop_register_timeout(wpa_s->sched_scan_timeout, 0, wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_s->first_sched_scan = 0; wpa_s->sched_scan_timeout /= 2; wpa_s->sched_scan_interval *= 2; if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) { wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; } } /* If there is no more ssids, start next time from the beginning */ if (!ssid) wpa_s->prev_sched_ssid = NULL; return 0; }