#include "hs20_supplicant.h"
#include "notify.h"
#include "bss.h"
+#include "gas_query.h"
#include "scan.h"
return 0;
}
+#endif /* CONFIG_P2P */
-/*
- * Find the operating frequency of any other virtual interface that is using
- * the same radio concurrently.
- */
-static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
+
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes,
+ enum hostapd_hw_mode mode)
{
- const char *rn, *rn2;
- struct wpa_supplicant *ifs;
- u8 bssid[ETH_ALEN];
+ u16 i;
- if (!wpa_s->driver->get_radio_name)
- return -1;
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode == mode)
+ return &modes[i];
+ }
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- if (rn == NULL || rn[0] == '\0')
- return -1;
+ return NULL;
+}
- for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
- continue;
- rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
- if (!rn2 || os_strcmp(rn, rn2) != 0)
- continue;
+static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band - use empty list */
+ params->freqs = os_zalloc(sizeof(int));
+ return;
+ }
- if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+ params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
-
- if (ifs->current_ssid->mode == WPAS_MODE_AP ||
- ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
- return ifs->current_ssid->frequency;
- if (wpa_drv_get_bssid(ifs, bssid) == 0)
- return ifs->assoc_freq;
+ params->freqs[count++] = mode->channels[i].freq;
}
-
- return 0;
}
-#endif /* CONFIG_P2P */
+
+static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ if (wpa_s->hw.modes == NULL)
+ return; /* unknown what channels the driver supports */
+ if (params->freqs)
+ return; /* already using a limited channel set */
+ if (wpa_s->setband == WPA_SETBAND_5G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params);
+ else if (wpa_s->setband == WPA_SETBAND_2G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ params);
+}
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#ifdef CONFIG_P2P
- if (wpas_p2p_in_progress(wpa_s)) {
+ if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) {
if (wpa_s->sta_scan_pending &&
wpas_p2p_in_progress(wpa_s) == 2 &&
wpa_s->global->p2p_cb_on_scan_complete) {
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_GAS
+ if (gas_query_in_progress(wpa_s->gas)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ return;
+ }
+#endif /* CONFIG_GAS */
+
if (wpa_s->conf->ap_scan == 2)
max_ssids = 1;
else {
#ifdef CONFIG_P2P
if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
wpa_s->go_params) {
- wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
- "P2P group formation");
+ wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
+ wpa_s->p2p_in_provisioning,
+ wpa_s->show_group_started);
params.ssids[0].ssid = wpa_s->go_params->ssid;
params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
params.num_ssids = 1;
} else
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ wpa_setband_scan_freqs(wpa_s, ¶ms);
+
+ /* See if user specified frequencies. If so, scan only those. */
+ if (wpa_s->conf->freq_list && !params.freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Optimize scan based on conf->freq_list");
+ int_array_concat(¶ms.freqs, wpa_s->conf->freq_list);
+ }
+
+ /* Use current associated channel? */
+ if (wpa_s->conf->scan_cur_freq && !params.freqs) {
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ params.freqs = os_calloc(num + 1, sizeof(int));
+ if (params.freqs) {
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ if (num > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
+ "current operating channels since "
+ "scan_cur_freq is enabled");
+ } else {
+ os_free(params.freqs);
+ params.freqs = NULL;
+ }
+ }
+ }
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, ¶ms.num_filter_ssids);
if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
!scan_params->freqs && !params.freqs &&
wpas_is_p2p_prioritized(wpa_s) &&
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
non_p2p_network_enabled(wpa_s)) {
- int freq = shared_vif_oper_freq(wpa_s);
- if (freq > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
- "operating channel (%d MHz) since driver does "
- "not support multi-channel concurrency", freq);
- params.freqs = os_zalloc(sizeof(int) * 2);
- if (params.freqs)
- params.freqs[0] = freq;
- scan_params->freqs = params.freqs;
+ unsigned int num = wpa_s->num_multichan_concurrent;
+
+ params.freqs = os_calloc(num + 1, sizeof(int));
+ if (params.freqs) {
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ if (num > 0 && num == wpa_s->num_multichan_concurrent) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
+ } else {
+ os_free(params.freqs);
+ params.freqs = NULL;
+ }
}
}
#endif /* CONFIG_P2P */
new_int.usec = remaining.usec;
}
- eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
- wpa_s, NULL);
+ if (cancelled) {
+ eloop_register_timeout(new_int.sec, new_int.usec,
+ wpa_supplicant_scan, wpa_s, NULL);
+ }
wpa_s->scan_interval = sec;
}
*/
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
- /* If there's at least one network that should be specifically scanned
- * then don't cancel the scan and reschedule. Some drivers do
- * background scanning which generates frequent scan results, and that
- * causes the specific SSID scan to get continually pushed back and
- * never happen, which causes hidden APs to never get probe-scanned.
- */
- if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
- wpa_s->conf->ap_scan == 1) {
- struct wpa_ssid *ssid = wpa_s->conf->ssid;
-
- while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid) &&
- ssid->scan_ssid)
- break;
- ssid = ssid->next;
- }
- if (ssid) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
- "ensure that specific SSID scans occur");
- return;
- }
+ if (eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL))
+ {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d sec %d usec",
+ sec, usec);
+ return;
}
wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
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->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);
}
+/**
+ * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a delayed scheduled scan.
+ */
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->sched_scan_supported)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan");
+ eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout,
+ wpa_s, NULL);
+}
+
+
/**
* wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
* @wpa_s: Pointer to wpa_supplicant data
}
+/**
+ * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ *
+ * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
+ u32 vendor_type)
+{
+ const u8 *end, *pos;
+
+ if (res->beacon_ie_len == 0)
+ return NULL;
+
+ pos = (const u8 *) (res + 1);
+ pos += res->ie_len;
+ end = pos + res->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
/**
* wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
* @res: Scan result entry