[PATCH] bgscan: Add centralized signal_monitor

Paul Stewart pstew at google.com
Mon Mar 28 16:34:59 EDT 2011


The signal strength number tells only half of the picture with
respect to signal quality.  The other half is the prevailing
noise on the channel.  The two together indicate how easily the
interface is able to pull data out of the background noise.

This change takes noise into account, by caclulating a CQM
threshold based both on the RSSI and noise.  This noise value is
available in the CQM events as well as polled data.  Since most
background scan algorithms will probably want to do this the same
way, I have added this as routines in bgscan.c that can be
utilized by individual background scan mechanisms.

Additionally, I've modified bgscan_simple to use this mechanism,
and scheduled noise floor updates to happen at the same rate as
background scans (the noisefloor should be a slowly changing
parameter).

Signed-off-by: Paul Stewart <pstew at google.com>

Change-Id: If5f8a54a5b028796874c924999adf01668866d35
---
 wpa_supplicant/bgscan.c        |   84 ++++++++++++++++++++++++++++++++++++++++
 wpa_supplicant/bgscan_i.h      |   72 ++++++++++++++++++++++++++++++++++
 wpa_supplicant/bgscan_simple.c |   25 ++++++++----
 3 files changed, 172 insertions(+), 9 deletions(-)
 create mode 100644 wpa_supplicant/bgscan_i.h

diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 5661830..5b051e0 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -17,7 +17,9 @@
 #include "common.h"
 #include "wpa_supplicant_i.h"
 #include "config_ssid.h"
+#include "driver_i.h"
 #include "bgscan.h"
+#include "bgscan_i.h"
 
 #ifdef CONFIG_BGSCAN_SIMPLE
 extern const struct bgscan_ops bgscan_simple_ops;
@@ -121,3 +123,85 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
 						    current_noise,
 						    current_txrate);
 }
+
+static void bgscan_apply_signal_monitor(void *eloop_ctx, void *timeout_ctx)
+{
+	struct bgscan_signal_monitor_state *sm_state = eloop_ctx;
+
+	wpa_drv_signal_monitor(sm_state->wpa_s, sm_state->calc_threshold,
+			       sm_state->hysteresis);
+}
+
+
+void bgscan_update_signal_monitor(struct bgscan_signal_monitor_state *sm_state,
+				 int current_signal, int current_noise)
+{
+	int threshold = current_noise + sm_state->headroom;
+
+	if (current_noise >= 0)
+		return;
+
+	if (threshold >= sm_state->calc_threshold -
+	    BGSCAN_NOISEFLOOR_TOLERANCE &&
+	    threshold <= sm_state->calc_threshold +
+	    BGSCAN_NOISEFLOOR_TOLERANCE)
+		return;
+
+	wpa_printf(MSG_DEBUG, "%s: noisefloor update: %d -> %d",
+		   __func__, sm_state->calc_threshold - sm_state->headroom,
+		   current_noise);
+
+	sm_state->calc_threshold = threshold;
+
+	/*
+	 * Schedule a noisefloor adjustment.  Do this as a timeout callback,
+	 * so it is implicitly throttled.
+	 */
+	eloop_cancel_timeout(bgscan_apply_signal_monitor, sm_state, NULL);
+	eloop_register_timeout(BGSCAN_NOISEFLOOR_UPDATE_DELAY, 0,
+			       bgscan_apply_signal_monitor, sm_state, NULL);
+}
+
+int bgscan_poll_signal_monitor(struct bgscan_signal_monitor_state *sm_state,
+			       struct wpa_signal_info *siginfo_ret)
+{
+	struct wpa_signal_info siginfo;
+	int ret;
+
+	ret = wpa_drv_signal_poll(sm_state->wpa_s, &siginfo);
+	if (ret != 0)
+		return ret;
+
+	wpa_printf(MSG_DEBUG, "%s: bgscan poll noisefloor: %d ",
+		   __func__, siginfo.current_noise);
+
+	bgscan_update_signal_monitor(sm_state, siginfo.current_signal,
+				     siginfo.current_noise);
+
+	if (siginfo_ret != 0)
+		memcpy(siginfo_ret, &siginfo, sizeof(siginfo));
+
+	return 0;
+}
+
+void bgscan_init_signal_monitor(struct bgscan_signal_monitor_state *sm_state,
+				struct wpa_supplicant *wpa_s,
+				int signal_threshold,
+				int hysteresis) {
+
+	sm_state->wpa_s = wpa_s;
+	sm_state->calc_threshold = signal_threshold;
+	sm_state->hysteresis = hysteresis;
+	sm_state->headroom = signal_threshold - BGSCAN_DEFAULT_NOISE_FLOOR;
+
+	if (wpa_drv_signal_monitor(wpa_s, signal_threshold, hysteresis) < 0)
+		wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable "
+			   "signal strength monitoring");
+}
+
+void bgscan_deinit_signal_monitor(struct bgscan_signal_monitor_state *sm_state)
+{
+	wpa_drv_signal_monitor(sm_state->wpa_s, 0, 0);
+	eloop_cancel_timeout(bgscan_apply_signal_monitor, sm_state, NULL);
+}
+
diff --git a/wpa_supplicant/bgscan_i.h b/wpa_supplicant/bgscan_i.h
new file mode 100644
index 0000000..3829158
--- /dev/null
+++ b/wpa_supplicant/bgscan_i.h
@@ -0,0 +1,72 @@
+/*
+ * WPA Supplicant - background scan and roaming interface
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef BGSCAN_I_H
+#define BGSCAN_I_H
+
+/*
+ * The signal monitoring code is an optional facility for bgscan algorithms
+ * that want to track both signal strength and noise floor (e.g. so they can
+ * make decisions based on received signal strength relative to noise floor).
+ *
+ * calc_threshold: Signal strength threshold for generating CQM events.
+ *     When signal strength passes above or below this value CQM events
+ *     are generated.  rssi_threshold is initialized from user-specified
+ *     options to the algorithm and then recalculated based on the current
+ *     noise floor.
+ * headroom: The the threshold for signal above the noisefloor for
+ *     generating CQM events.  headroom is calculated at initialization
+ *     from the user-specified signal strength and then used to calculate
+ *     calc_threshold using the current noise floor.
+ * hysteresis: Hysterisis value passed into the driver CQM to indicate
+ *     how large a delta in received signal (in dBm) from the last CQM
+ *     event should trigger another CQM event.
+ */
+struct bgscan_signal_monitor_state {
+	struct wpa_supplicant *wpa_s;
+	int calc_threshold;
+	int headroom;
+	int hysteresis;
+};
+
+void bgscan_init_signal_monitor(struct bgscan_signal_monitor_state *sm_state,
+				struct wpa_supplicant *wpa_s,
+				int signal_threshold,
+				int hysteresis);
+void bgscan_deinit_signal_monitor(struct bgscan_signal_monitor_state *sm_state);
+void bgscan_udpate_signal_monitor(struct bgscan_signal_monitor_state *sm_state,
+				  int current_signal, int current_noise);
+int bgscan_poll_signal_monitor(struct bgscan_signal_monitor_state *sm_state,
+			       struct wpa_signal_info *siginfo_ret);
+
+
+/*
+ * The time (secs) to delay updates to the CQM monitoring parameters.  This is
+ * done to collapse rapid changes into a single request.
+ */
+#define BGSCAN_NOISEFLOOR_UPDATE_DELAY 10
+
+/*
+ * The starting/default noise floor for the channel (dBm).  This also
+ * serves as the reference noise floor for user-specified signal strength
+ * values in bgscan algorithms that use these facilities.
+ */
+#define BGSCAN_DEFAULT_NOISE_FLOOR -95
+
+/*
+ * Range [+/-] for determining if the noise floor has changed enough for
+ * us to adjust the RSSI threshold.
+ */
+#define BGSCAN_NOISEFLOOR_TOLERANCE 1
+#endif /* BGSCAN_I_H */
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 7963302..eed7b83 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -22,6 +22,7 @@
 #include "driver_i.h"
 #include "scan.h"
 #include "bgscan.h"
+#include "bgscan_i.h"
 
 struct bgscan_simple_data {
 	struct wpa_supplicant *wpa_s;
@@ -32,6 +33,7 @@ struct bgscan_simple_data {
 	int short_interval; /* use if signal < threshold */
 	int long_interval; /* use if signal > threshold */
 	struct os_time last_bgscan;
+	struct bgscan_signal_monitor_state signal_monitor;
 };
 
 
@@ -131,17 +133,16 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
 		   data->signal_threshold, data->short_interval,
 		   data->long_interval);
 
-	if (data->signal_threshold &&
-	    wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
-		wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable "
-			   "signal strength monitoring");
-	}
-
 	data->scan_interval = data->short_interval;
 	if (data->signal_threshold) {
-		/* Poll for signal info to set initial scan interval */
 		struct wpa_signal_info siginfo;
-		if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+
+		bgscan_init_signal_monitor(&data->signal_monitor, wpa_s,
+					   data->signal_threshold, 4);
+
+		/* Poll for signal info to set initial scan interval */
+		if (bgscan_poll_signal_monitor(&data->signal_monitor,
+					       &siginfo) == 0 &&
 		    siginfo.current_signal >= data->signal_threshold)
 			data->scan_interval = data->long_interval;
 	}
@@ -167,7 +168,7 @@ static void bgscan_simple_deinit(void *priv)
 	struct bgscan_simple_data *data = priv;
 	eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
 	if (data->signal_threshold)
-		wpa_drv_signal_monitor(data->wpa_s, 0, 0);
+		bgscan_deinit_signal_monitor(&data->signal_monitor);
 	os_free(data);
 }
 
@@ -179,6 +180,8 @@ static int bgscan_simple_notify_scan(void *priv,
 
 	wpa_printf(MSG_DEBUG, "bgscan simple: scan result notification");
 
+	if (data->signal_threshold)
+		bgscan_poll_signal_monitor(&data->signal_monitor, NULL);
 	eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
 	eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
 			       data, NULL);
@@ -218,6 +221,10 @@ static void bgscan_simple_notify_signal_change(void *priv, int above,
 		   "(above=%d current_signal=%d current_noise=%d "
 		   "current_txrate=%d))", above, current_signal,
 		   current_noise, current_txrate);
+
+	bgscan_update_signal_monitor(&data->signal_monitor, current_signal,
+				     current_noise);
+
 	if (data->scan_interval == data->long_interval && !above) {
 		wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
 			   "bgscan interval");
-- 
1.7.3.1



More information about the HostAP mailing list