bgscan: Add signal strength change events
authorJouni Malinen <j@w1.fi>
Sun, 28 Mar 2010 22:32:34 +0000 (15:32 -0700)
committerJouni Malinen <j@w1.fi>
Sun, 28 Mar 2010 22:32:34 +0000 (15:32 -0700)
This allows bgscan modules to use more information to decide on when
to perform background scans. bgscan_simple can now change between
short and long background scan intervals based on signal strength
and in addition, it can trigger immediate scans when the signal
strength is detected to be dropping.

bgscan_simple takes following parameters now:
short interval:signal strength threshold:long interval
For example:
bgscan="simple:30:-45:300"

wpa_supplicant/bgscan.c
wpa_supplicant/bgscan.h
wpa_supplicant/bgscan_simple.c
wpa_supplicant/events.c

index 60dcd0d..31b5d27 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - background scan and roaming interface
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2010, Jouni Malinen <j@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
@@ -103,8 +103,8 @@ void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
 }
 
 
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s)
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above)
 {
        if (wpa_s->bgscan && wpa_s->bgscan_priv)
-               wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv);
+               wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above);
 }
index dfd4cab..69e99b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - background scan and roaming interface
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2010, Jouni Malinen <j@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
@@ -27,7 +27,7 @@ struct bgscan_ops {
 
        int (*notify_scan)(void *priv);
        void (*notify_beacon_loss)(void *priv);
-       void (*notify_signal_change)(void *priv);
+       void (*notify_signal_change)(void *priv, int above);
 };
 
 #ifdef CONFIG_BGSCAN
@@ -36,7 +36,7 @@ int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 void bgscan_deinit(struct wpa_supplicant *wpa_s);
 int bgscan_notify_scan(struct wpa_supplicant *wpa_s);
 void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s);
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above);
 
 #else /* CONFIG_BGSCAN */
 
@@ -59,7 +59,8 @@ static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
 {
 }
 
-static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s)
+static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
+                                              int above)
 {
 }
 
index bf780d5..a932553 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - background scan and roaming module: simple
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2010, Jouni Malinen <j@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
@@ -19,6 +19,7 @@
 #include "drivers/driver.h"
 #include "config_ssid.h"
 #include "wpa_supplicant_i.h"
+#include "driver_i.h"
 #include "scan.h"
 #include "bgscan.h"
 
@@ -26,6 +27,10 @@ struct bgscan_simple_data {
        struct wpa_supplicant *wpa_s;
        const struct wpa_ssid *ssid;
        int scan_interval;
+       int signal_threshold;
+       int short_interval; /* use if signal < threshold */
+       int long_interval; /* use if signal > threshold */
+       struct os_time last_bgscan;
 };
 
 
@@ -52,7 +57,36 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
                wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
                eloop_register_timeout(data->scan_interval, 0,
                                       bgscan_simple_timeout, data, NULL);
+       } else
+               os_get_time(&data->last_bgscan);
+}
+
+
+static int bgscan_simple_get_params(struct bgscan_simple_data *data,
+                                   const char *params)
+{
+       const char *pos;
+
+       if (params == NULL)
+               return 0;
+
+       data->short_interval = atoi(params);
+
+       pos = os_strchr(params, ':');
+       if (pos == NULL)
+               return 0;
+       pos++;
+       data->signal_threshold = atoi(pos);
+       pos = os_strchr(pos, ':');
+       if (pos == NULL) {
+               wpa_printf(MSG_ERROR, "bgscan simple: Missing scan interval "
+                          "for high signal");
+               return -1;
        }
+       pos++;
+       data->long_interval = atoi(pos);
+
+       return 0;
 }
 
 
@@ -67,10 +101,27 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
                return NULL;
        data->wpa_s = wpa_s;
        data->ssid = ssid;
-       if (params)
-               data->scan_interval = atoi(params);
-       if (data->scan_interval <= 0)
-               data->scan_interval = 30;
+       if (bgscan_simple_get_params(data, params) < 0) {
+               os_free(data);
+               return NULL;
+       }
+       if (data->short_interval <= 0)
+               data->short_interval = 30;
+       if (data->long_interval <= 0)
+               data->long_interval = 30;
+
+       wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d  "
+                  "Short bgscan interval %d  Long bgscan interval %d",
+                  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;
        eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
                               data, NULL);
        return data;
@@ -81,6 +132,8 @@ 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);
        os_free(data);
 }
 
@@ -113,11 +166,46 @@ static void bgscan_simple_notify_beacon_loss(void *priv)
 }
 
 
-static void bgscan_simple_notify_signal_change(void *priv)
+static void bgscan_simple_notify_signal_change(void *priv, int above)
 {
-       wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed");
-       /* TODO: if signal strength dropped enough, speed up background
-        * scanning */
+       struct bgscan_simple_data *data = priv;
+
+       if (data->short_interval == data->long_interval ||
+           data->signal_threshold == 0)
+               return;
+
+       wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed "
+                  "(above=%d)", above);
+       if (data->scan_interval == data->long_interval && !above) {
+               wpa_printf(MSG_DEBUG, "bgscan simple: Trigger immediate scan "
+                          "and start using short bgscan interval");
+               data->scan_interval = data->short_interval;
+               eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+               eloop_register_timeout(0, 0, bgscan_simple_timeout, data,
+                                      NULL);
+       } else if (data->scan_interval == data->short_interval && above) {
+               wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan "
+                          "interval");
+               data->scan_interval = data->long_interval;
+               eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+               eloop_register_timeout(data->scan_interval, 0,
+                                      bgscan_simple_timeout, data, NULL);
+       } else if (!above) {
+               struct os_time now;
+               /*
+                * Signal dropped further 4 dB. Request a new scan if we have
+                * not yet scanned in a while.
+                */
+               os_get_time(&now);
+               if (now.sec > data->last_bgscan.sec + 10) {
+                       wpa_printf(MSG_DEBUG, "bgscan simple: Trigger "
+                                  "immediate scan");
+                       eloop_cancel_timeout(bgscan_simple_timeout, data,
+                                            NULL);
+                       eloop_register_timeout(0, 0, bgscan_simple_timeout,
+                                              data, NULL);
+               }
+       }
 }
 
 
index 70dccac..734e7e9 100644 (file)
@@ -1740,6 +1740,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                        data->eapol_rx.data,
                                        data->eapol_rx.data_len);
                break;
+       case EVENT_SIGNAL_CHANGE:
+               bgscan_notify_signal_change(
+                       wpa_s, data->signal_change.above_threshold);
+               break;
        default:
                wpa_printf(MSG_INFO, "Unknown event %d", event);
                break;