Example #1
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 = 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(&params, 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, &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;
    }

    return 0;
}
Example #2
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(&params, 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, &params);

	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, &params,
					      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;
}
Example #3
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(&params, 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 = &params;

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;
}