]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/scan.c
Use radio work for P2P scan requests
[thirdparty/hostap.git] / wpa_supplicant / scan.c
index 372685718d85c0c6d0f3a48f56ff3f076d492e49..b36c87c6e9a2ed8ad8c438dab29b623222ab6030 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Scanning
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -142,6 +142,40 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
+{
+       struct wpa_supplicant *wpa_s = work->wpa_s;
+       struct wpa_driver_scan_params *params = work->ctx;
+       int ret;
+
+       if (deinit) {
+               wpa_scan_free_params(params);
+               return;
+       }
+
+       wpa_supplicant_notify_scanning(wpa_s, 1);
+
+       if (wpa_s->clear_driver_scan_cache)
+               params->only_new_results = 1;
+       ret = wpa_drv_scan(wpa_s, params);
+       wpa_scan_free_params(params);
+       work->ctx = NULL;
+       if (ret) {
+               wpa_supplicant_notify_scanning(wpa_s, 0);
+               wpas_notify_scan_done(wpa_s, 0);
+               radio_work_done(work);
+               return;
+       }
+
+       os_get_reltime(&wpa_s->scan_trigger_time);
+       wpa_s->scan_runs++;
+       wpa_s->normal_scans++;
+       wpa_s->own_scan_requested = 1;
+       wpa_s->clear_driver_scan_cache = 0;
+       wpa_s->scan_work = work;
+}
+
+
 /**
  * wpa_supplicant_trigger_scan - Request driver to start a scan
  * @wpa_s: Pointer to wpa_supplicant data
@@ -151,22 +185,24 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
                                struct wpa_driver_scan_params *params)
 {
-       int ret;
+       struct wpa_driver_scan_params *ctx;
 
-       wpa_supplicant_notify_scanning(wpa_s, 1);
+       if (wpa_s->scan_work) {
+               wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
+               return -1;
+       }
 
-       ret = wpa_drv_scan(wpa_s, params);
-       if (ret) {
-               wpa_supplicant_notify_scanning(wpa_s, 0);
-               wpas_notify_scan_done(wpa_s, 0);
-       } else {
-               os_get_reltime(&wpa_s->scan_trigger_time);
-               wpa_s->scan_runs++;
-               wpa_s->normal_scans++;
-               wpa_s->own_scan_requested = 1;
+       ctx = wpa_scan_clone_params(params);
+       if (ctx == NULL)
+               return -1;
+
+       if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+       {
+               wpa_scan_free_params(ctx);
+               return -1;
        }
 
-       return ret;
+       return 0;
 }
 
 
@@ -488,14 +524,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
-               wpas_p2p_continue_after_scan(wpa_s);
                return;
        }
 
        if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-               wpas_p2p_continue_after_scan(wpa_s);
                return;
        }
 
@@ -524,7 +558,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
            wpa_s->scan_req == NORMAL_SCAN_REQ) {
                wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-               wpas_p2p_continue_after_scan(wpa_s);
                return;
        }
 
@@ -543,18 +576,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 
 #ifdef CONFIG_P2P
        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) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
-                               "mode scan during P2P search");
-               } else {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
-                               "while P2P operation is in progress");
-                       wpa_s->sta_scan_pending = 1;
-                       wpa_supplicant_req_scan(wpa_s, 5, 0);
-                       return;
-               }
+               wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
+               wpa_supplicant_req_scan(wpa_s, 5, 0);
+               return;
        }
 #endif /* CONFIG_P2P */
 
@@ -727,6 +751,10 @@ ssid_list_set:
        wpa_supplicant_optimize_freqs(wpa_s, &params);
        extra_ie = wpa_supplicant_extra_ies(wpa_s);
 
+       if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+           wpa_s->manual_scan_only_new)
+               params.only_new_results = 1;
+
        if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
            wpa_s->manual_scan_freqs) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
@@ -1162,7 +1190,6 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
 {
        wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
        eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-       wpas_p2p_continue_after_scan(wpa_s);
 }
 
 
@@ -1630,7 +1657,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
        filter_scan_res(wpa_s, scan_res);
 
 #ifdef CONFIG_WPS
-       if (wpas_wps_in_progress(wpa_s)) {
+       if (wpas_wps_searching(wpa_s)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
                        "provisioning rules");
                compar = wpa_scan_result_wps_compar;
@@ -1692,6 +1719,11 @@ void scan_only_handler(struct wpa_supplicant *wpa_s,
        }
        wpas_notify_scan_results(wpa_s);
        wpas_notify_scan_done(wpa_s, 1);
+       if (wpa_s->scan_work) {
+               struct wpa_radio_work *work = wpa_s->scan_work;
+               wpa_s->scan_work = NULL;
+               radio_work_done(work);
+       }
 }
 
 
@@ -1699,3 +1731,82 @@ int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
 {
        return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
 }
+
+
+struct wpa_driver_scan_params *
+wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
+{
+       struct wpa_driver_scan_params *params;
+       size_t i;
+       u8 *n;
+
+       params = os_zalloc(sizeof(*params));
+       if (params == NULL)
+               return NULL;
+
+       for (i = 0; i < src->num_ssids; i++) {
+               if (src->ssids[i].ssid) {
+                       n = os_malloc(src->ssids[i].ssid_len);
+                       if (n == NULL)
+                               goto failed;
+                       os_memcpy(n, src->ssids[i].ssid,
+                                 src->ssids[i].ssid_len);
+                       params->ssids[i].ssid = n;
+                       params->ssids[i].ssid_len = src->ssids[i].ssid_len;
+               }
+       }
+       params->num_ssids = src->num_ssids;
+
+       if (src->extra_ies) {
+               n = os_malloc(src->extra_ies_len);
+               if (n == NULL)
+                       goto failed;
+               os_memcpy(n, src->extra_ies, src->extra_ies_len);
+               params->extra_ies = n;
+               params->extra_ies_len = src->extra_ies_len;
+       }
+
+       if (src->freqs) {
+               int len = int_array_len(src->freqs);
+               params->freqs = os_malloc((len + 1) * sizeof(int));
+               if (params->freqs == NULL)
+                       goto failed;
+               os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int));
+       }
+
+       if (src->filter_ssids) {
+               params->filter_ssids = os_malloc(sizeof(params->filter_ssids) *
+                                                src->num_filter_ssids);
+               if (params->filter_ssids == NULL)
+                       goto failed;
+               os_memcpy(params->filter_ssids, src->filter_ssids,
+                         sizeof(params->filter_ssids) * src->num_filter_ssids);
+               params->num_filter_ssids = src->num_filter_ssids;
+       }
+
+       params->filter_rssi = src->filter_rssi;
+       params->p2p_probe = src->p2p_probe;
+       params->only_new_results = src->only_new_results;
+
+       return params;
+
+failed:
+       wpa_scan_free_params(params);
+       return NULL;
+}
+
+
+void wpa_scan_free_params(struct wpa_driver_scan_params *params)
+{
+       size_t i;
+
+       if (params == NULL)
+               return;
+
+       for (i = 0; i < params->num_ssids; i++)
+               os_free((u8 *) params->ssids[i].ssid);
+       os_free((u8 *) params->extra_ies);
+       os_free(params->freqs);
+       os_free(params->filter_ssids);
+       os_free(params);
+}