Browse Source

Use radio work for scan requests

Avoid concurrent scan requests by using the radio work queuing
mechanism.

Signed-hostap: Jouni Malinen <j@w1.fi>
Jouni Malinen 11 years ago
parent
commit
d12a51b5d2
4 changed files with 95 additions and 42 deletions
  1. 34 27
      wpa_supplicant/events.c
  2. 53 15
      wpa_supplicant/scan.c
  3. 7 0
      wpa_supplicant/wpa_supplicant.c
  4. 1 0
      wpa_supplicant/wpa_supplicant_i.h

+ 34 - 27
wpa_supplicant/events.c

@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Driver event processing
- * 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.
@@ -1181,7 +1181,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 					      union wpa_event_data *data,
 					      int own_request)
 {
-	struct wpa_scan_results *scan_res;
+	struct wpa_scan_results *scan_res = NULL;
+	int ret = 0;
 	int ap = 0;
 #ifndef CONFIG_NO_RANDOM_POOL
 	size_t i, num;
@@ -1206,7 +1207,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 			wpa_s->scan_req = wpa_s->last_scan_req;
 			wpa_s->sta_scan_pending = 1;
 			wpa_supplicant_req_scan(wpa_s, 5, 0);
-			return -1;
+			ret = -1;
+			goto scan_work_done;
 		}
 	}
 	wpa_s->sta_scan_pending = 0;
@@ -1224,7 +1226,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
 			"scanning again");
 		wpa_supplicant_req_new_scan(wpa_s, 1, 0);
-		return -1;
+		ret = -1;
+		goto scan_work_done;
 	}
 
 #ifndef CONFIG_NO_RANDOM_POOL
@@ -1251,9 +1254,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		scan_res_handler = wpa_s->scan_res_handler;
 		wpa_s->scan_res_handler = NULL;
 		scan_res_handler(wpa_s, scan_res);
-
-		wpa_scan_results_free(scan_res);
-		return -2;
+		ret = -2;
+		goto scan_work_done;
 	}
 
 	if (ap) {
@@ -1262,8 +1264,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		if (wpa_s->ap_iface->scan_cb)
 			wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
 #endif /* CONFIG_AP */
-		wpa_scan_results_free(scan_res);
-		return 0;
+		goto scan_work_done;
 	}
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
@@ -1286,38 +1287,44 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 		return 0;
 	}
 
-	if (sme_proc_obss_scan(wpa_s) > 0) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	if (sme_proc_obss_scan(wpa_s) > 0)
+		goto scan_work_done;
 
-	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
+		goto scan_work_done;
 
-	if (autoscan_notify_scan(wpa_s, scan_res)) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	if (autoscan_notify_scan(wpa_s, scan_res))
+		goto scan_work_done;
 
 	if (wpa_s->disconnected) {
 		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-		wpa_scan_results_free(scan_res);
-		return 0;
+		goto scan_work_done;
 	}
 
 	if (!wpas_driver_bss_selection(wpa_s) &&
-	    bgscan_notify_scan(wpa_s, scan_res) == 1) {
-		wpa_scan_results_free(scan_res);
-		return 0;
-	}
+	    bgscan_notify_scan(wpa_s, scan_res) == 1)
+		goto scan_work_done;
 
 	wpas_wps_update_ap_info(wpa_s, scan_res);
 
 	wpa_scan_results_free(scan_res);
 
+	if (wpa_s->scan_work) {
+		struct wpa_radio_work *work = wpa_s->scan_work;
+		wpa_s->scan_work = NULL;
+		radio_work_done(work);
+	}
+
 	return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
+
+scan_work_done:
+	wpa_scan_results_free(scan_res);
+	if (wpa_s->scan_work) {
+		struct wpa_radio_work *work = wpa_s->scan_work;
+		wpa_s->scan_work = NULL;
+		radio_work_done(work);
+	}
+	return ret;
 }
 
 

+ 53 - 15
wpa_supplicant/scan.c

@@ -142,34 +142,67 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
 }
 
 
-/**
- * wpa_supplicant_trigger_scan - Request driver to start a scan
- * @wpa_s: Pointer to wpa_supplicant data
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params)
+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);
-	} else {
-		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;
+		radio_work_done(work);
+		return;
 	}
 
-	return ret;
+	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
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_scan_params *ctx;
+
+	if (wpa_s->scan_work) {
+		wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
+		return -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 0;
 }
 
 
@@ -1699,6 +1732,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);
+	}
 }
 
 

+ 7 - 0
wpa_supplicant/wpa_supplicant.c

@@ -2903,6 +2903,13 @@ static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
 
 static void radio_work_free(struct wpa_radio_work *work)
 {
+	if (work->wpa_s->scan_work == work) {
+		/* This should not really happen. */
+		wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
+			work->type, work, work->started);
+		work->wpa_s->scan_work = NULL;
+	}
+
 	dl_list_del(&work->list);
 	os_free(work);
 }

+ 1 - 0
wpa_supplicant/wpa_supplicant_i.h

@@ -442,6 +442,7 @@ struct wpa_supplicant {
 	struct ctrl_iface_priv *ctrl_iface;
 
 	enum wpa_states wpa_state;
+	struct wpa_radio_work *scan_work;
 	int scanning;
 	int sched_scanning;
 	int new_connection;