---
 plugins/wifi.c |  201 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 183 insertions(+), 18 deletions(-)

diff --git a/plugins/wifi.c b/plugins/wifi.c
index ea7686c..8fef7c8 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -69,6 +69,17 @@ struct hidden_params {
        char *passphrase;
 };
 
+/**
+ * Used for autoscan "emulation".
+ * Should be removed when wpa_s autoscan support will be by default.
+ */
+struct autoscan_params {
+       int base;
+       int limit;
+       int interval;
+       unsigned int timeout;
+};
+
 struct wifi_data {
        char *identifier;
        struct connman_device *device;
@@ -87,6 +98,10 @@ struct wifi_data {
        unsigned int watch;
        int retries;
        struct hidden_params *hidden;
+       /**
+        * autoscan "emulation".
+        */
+       struct autoscan_params *autoscan;
 };
 
 static GList *iface_list = NULL;
@@ -186,6 +201,27 @@ static void remove_networks(struct connman_device *device,
        wifi->networks = NULL;
 }
 
+static void stop_autoscan(struct connman_device *device)
+{
+       struct wifi_data *wifi = connman_device_get_data(device);
+       struct autoscan_params *autoscan;
+
+       DBG("");
+
+       if (wifi == NULL || wifi->autoscan == NULL)
+               return;
+
+       autoscan = wifi->autoscan;
+
+       if (autoscan->timeout > 0)
+               g_source_remove(autoscan->timeout);
+
+       autoscan->timeout = 0;
+       autoscan->interval = 0;
+
+       connman_device_unref(device);
+}
+
 static void wifi_remove(struct connman_device *device)
 {
        struct wifi_data *wifi = connman_device_get_data(device);
@@ -195,6 +231,8 @@ static void wifi_remove(struct connman_device *device)
        if (wifi == NULL)
                return;
 
+       stop_autoscan(device);
+
        iface_list = g_list_remove(iface_list, wifi);
 
        remove_networks(device, wifi);
@@ -206,16 +244,148 @@ static void wifi_remove(struct connman_device *device)
 
        g_supplicant_interface_set_data(wifi->interface, NULL);
 
+       g_free(wifi->autoscan);
        g_free(wifi->identifier);
        g_free(wifi);
 }
 
+static int _wifi_scan(struct connman_device *device,
+                       GSupplicantInterfaceCallback callback)
+{
+       struct wifi_data *wifi = connman_device_get_data(device);
+       int ret;
+
+       DBG("device %p %p", device, wifi->interface);
+
+       if (wifi->tethering == TRUE)
+               return 0;
+
+       connman_device_ref(device);
+
+       ret = g_supplicant_interface_scan(wifi->interface, NULL,
+                                               callback, device);
+       if (ret == 0)
+               connman_device_set_scanning(device, TRUE);
+       else
+               connman_device_unref(device);
+
+       return ret;
+}
+
+static void autoscan_scan_callback(int result,
+                       GSupplicantInterface *interface, void *user_data)
+{
+       struct connman_device *device = user_data;
+
+       DBG("");
+
+       connman_device_set_scanning(device, FALSE);
+}
+
+static gboolean autoscan_timeout(gpointer data)
+{
+       struct connman_device *device = data;
+       struct wifi_data *wifi = connman_device_get_data(device);
+       struct autoscan_params *autoscan;
+       int interval;
+
+       autoscan = wifi->autoscan;
+
+       if (autoscan->interval <= 0) {
+               interval = autoscan->base;
+               goto set_interval;
+       } else if (autoscan->interval >= autoscan->limit)
+               interval = autoscan->limit;
+       else
+               interval = autoscan->interval * autoscan->base;
+
+       _wifi_scan(wifi->device, autoscan_scan_callback);
+
+set_interval:
+       DBG("interval %d", interval);
+
+       autoscan->interval = interval;
+
+       autoscan->timeout = g_timeout_add_seconds(interval,
+                                               autoscan_timeout, device);
+
+       return FALSE;
+}
+
+static void start_autoscan(struct connman_device *device)
+{
+       struct wifi_data *wifi = connman_device_get_data(device);
+       struct autoscan_params *autoscan;
+
+       DBG("");
+
+       if (wifi == NULL)
+               return;
+
+       autoscan = wifi->autoscan;
+       if (autoscan == NULL)
+               return;
+
+       if (autoscan->timeout > 0 || autoscan->interval > 0)
+               return;
+
+       connman_device_ref(device);
+
+       autoscan_timeout(device);
+}
+
+static struct autoscan_params *parse_autoscan_params(const char *params)
+{
+       struct autoscan_params *autoscan;
+       char **list_params;
+       int limit;
+       int base;
+
+       DBG("Emulating autoscan");
+
+       list_params = g_strsplit(params, ":", 0);
+       if (list_params == 0)
+               return NULL;
+
+       if (g_strv_length(list_params) < 3) {
+               g_strfreev(list_params);
+               return NULL;
+       }
+
+       base = atoi(list_params[1]);
+       limit = atoi(list_params[2]);
+
+       g_strfreev(list_params);
+
+       autoscan = g_try_malloc0(sizeof(struct autoscan_params));
+       if (autoscan == NULL) {
+               DBG("Could not allocate memory for autoscan");
+               return NULL;
+       }
+
+       DBG("base %d - limit %d", base, limit);
+       autoscan->base = base;
+       autoscan->limit = limit;
+
+       return autoscan;
+}
+
+static void setup_autoscan(struct wifi_data *wifi)
+{
+       if (wifi->autoscan == NULL)
+               wifi->autoscan = parse_autoscan_params(AUTOSCAN_DEFAULT);
+
+       start_autoscan(wifi->device);
+}
+
 static void interface_autoscan_callback(int result,
                                        GSupplicantInterface *interface,
                                                        void *user_data)
 {
-       if (result < 0)
+       if (result < 0) {
                DBG("Could not enable Autoscan");
+               setup_autoscan(user_data);
+       }
 }
 
 static void interface_create_callback(int result,
@@ -247,8 +417,10 @@ static void interface_create_callback(int result,
        connman_device_set_powered(wifi->device, TRUE);
 
        if (g_supplicant_interface_autoscan(interface, AUTOSCAN_DEFAULT,
-                                       interface_autoscan_callback, wifi) < 0)
+                               interface_autoscan_callback, wifi) < 0) {
                DBG("Could not enable Autoscan");
+               setup_autoscan(wifi);
+       }
 }
 
 static int wifi_enable(struct connman_device *device)
@@ -319,6 +491,8 @@ static void scan_callback(int result, GSupplicantInterface 
*interface,
 
        connman_device_set_scanning(device, FALSE);
        connman_device_unref(device);
+
+       start_autoscan(device);
 }
 
 static int add_scan_param(gchar *hex_ssid, int freq,
@@ -492,23 +666,9 @@ static int get_latest_connections(int max_ssids,
 
 static int wifi_scan(struct connman_device *device)
 {
-       struct wifi_data *wifi = connman_device_get_data(device);
-       int ret;
+       stop_autoscan(device);
 
-       DBG("device %p %p", device, wifi->interface);
-
-       if (wifi->tethering == TRUE)
-               return 0;
-
-       connman_device_ref(device);
-       ret = g_supplicant_interface_scan(wifi->interface, NULL,
-                                       scan_callback, device);
-       if (ret == 0)
-               connman_device_set_scanning(device, TRUE);
-       else
-               connman_device_unref(device);
-
-       return ret;
+       return _wifi_scan(device, scan_callback);
 }
 
 static int wifi_scan_fast(struct connman_device *device)
@@ -539,6 +699,8 @@ static int wifi_scan_fast(struct connman_device *device)
                return wifi_scan(device);
        }
 
+       stop_autoscan(device);
+
        connman_device_ref(device);
        ret = g_supplicant_interface_scan(wifi->interface, scan_params,
                                                scan_callback, device);
@@ -587,6 +749,8 @@ static int wifi_scan_hidden(struct connman_device *device,
        hidden->passphrase = g_strdup(passphrase);
        wifi->hidden = hidden;
 
+       stop_autoscan(device);
+
        connman_device_ref(device);
        ret = g_supplicant_interface_scan(wifi->interface, scan_params,
                        scan_callback, device);
@@ -814,6 +978,7 @@ static void disconnect_callback(int result, 
GSupplicantInterface *interface,
                wifi->pending_network = NULL;
        }
 
+       start_autoscan(wifi->device);
 }
 
 static int network_disconnect(struct connman_network *network)
-- 
1.7.8.5

_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to