For fast scan append ssids and frequencies to scan request so
wpa_supplicant will only issue active scans for these passed
in frequencies.
---
 gsupplicant/gsupplicant.h |   16 ++++
 gsupplicant/supplicant.c  |  144 +++++++++++++++++++++++++++++--
 plugins/wifi.c            |  216 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 368 insertions(+), 8 deletions(-)

diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index a634141..848ceb5 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -73,6 +73,8 @@ extern "C" {
 #define G_SUPPLICANT_PAIRWISE_TKIP     (1 << 1)
 #define G_SUPPLICANT_PAIRWISE_CCMP     (1 << 2)
 
+#define G_SUPPLICANT_MAX_FAST_SCAN     4
+
 typedef enum {
        G_SUPPLICANT_MODE_UNKNOWN,
        G_SUPPLICANT_MODE_INFRA,
@@ -131,6 +133,19 @@ struct _GSupplicantSSID {
 
 typedef struct _GSupplicantSSID GSupplicantSSID;
 
+struct _GSupplicantScanParams {
+       struct scan_ssid {
+               void *ssid;
+               unsigned int ssid_len;
+       } ssids[G_SUPPLICANT_MAX_FAST_SCAN];
+
+       int num_ssids;
+
+       int freqs[G_SUPPLICANT_MAX_FAST_SCAN];
+};
+
+typedef struct _GSupplicantScanParams GSupplicantScanParams;
+
 /* global API */
 typedef void (*GSupplicantCountryCallback) (void *user_data);
 
@@ -155,6 +170,7 @@ int g_supplicant_interface_remove(GSupplicantInterface 
*interface,
                                        GSupplicantInterfaceCallback callback,
                                                        void *user_data);
 int g_supplicant_interface_scan(GSupplicantInterface *interface,
+                                       GSupplicantScanParams *scan_data,
                                        GSupplicantInterfaceCallback callback,
                                                        void *user_data);
 
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index e74001b..0b0b04f 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -2097,6 +2097,13 @@ struct interface_connect_data {
        void *user_data;
 };
 
+struct interface_scan_data {
+       GSupplicantInterface *interface;
+       GSupplicantInterfaceCallback callback;
+       GSupplicantScanParams *scan_params;
+       void *user_data;
+};
+
 static void interface_create_property(const char *key, DBusMessageIter *iter,
                                                        void *user_data)
 {
@@ -2349,10 +2356,23 @@ int g_supplicant_interface_remove(GSupplicantInterface 
*interface,
                                                interface_remove_result, data);
 }
 
+static void free_scan_data(GSupplicantScanParams *scan_data)
+{
+       int i;
+
+       if (!scan_data)
+               return;
+
+       for (i = 0; i < scan_data->num_ssids; i++)
+               g_free(scan_data->ssids[i].ssid);
+
+       g_free(scan_data);
+}
+
 static void interface_scan_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
-       struct interface_data *data = user_data;
+       struct interface_scan_data *data = user_data;
 
        if (error != NULL) {
                if (data->callback != NULL)
@@ -2362,27 +2382,133 @@ static void interface_scan_result(const char *error,
                data->interface->scan_data = data->user_data;
        }
 
+       if (user_data)
+               free_scan_data(data->scan_params);
+
        dbus_free(data);
 }
 
+static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq)
+{
+       DBusMessageIter data;
+       unsigned int width;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data);
+
+       dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq);
+       dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width);
+
+       dbus_message_iter_close_container(iter, &data);
+}
+
+static void add_scan_frequencies(DBusMessageIter *iter,
+                                               void *user_data)
+{
+       GSupplicantScanParams *scan_data = user_data;
+       unsigned int freq;
+       int i;
+
+       for (i = 0; i < G_SUPPLICANT_MAX_FAST_SCAN; i++) {
+               freq = scan_data->freqs[i];
+               if (!freq)
+                       break;
+
+               add_scan_frequency(iter, freq);
+       }
+}
+
+static void append_ssid(DBusMessageIter *iter,
+                       const void *ssid, unsigned int len)
+{
+       DBusMessageIter array;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+       DBUS_TYPE_BYTE_AS_STRING, &array);
+
+       dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+                                                               &ssid, len);
+       dbus_message_iter_close_container(iter, &array);
+}
+
+static void append_ssids(DBusMessageIter *iter, void *user_data)
+{
+       GSupplicantScanParams *scan_data = user_data;
+       int i;
+
+       for (i = 0; i < scan_data->num_ssids; i++)
+               append_ssid(iter, scan_data->ssids[i].ssid,
+                                       scan_data->ssids[i].ssid_len);
+}
+
+static void supplicant_add_scan_frequency(DBusMessageIter *dict,
+               const char *key, supplicant_dbus_array_function function,
+                                       void *user_data)
+{
+       DBusMessageIter entry, value, array;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+                               DBUS_TYPE_ARRAY_AS_STRING
+                               DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_UINT32_AS_STRING
+                               DBUS_TYPE_UINT32_AS_STRING
+                               DBUS_STRUCT_END_CHAR_AS_STRING, &value);
+
+       dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+                       DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_UINT32_AS_STRING
+                       DBUS_TYPE_UINT32_AS_STRING
+                       DBUS_STRUCT_END_CHAR_AS_STRING, &array);
+
+       if (function)
+               function(&array, user_data);
+
+       dbus_message_iter_close_container(&value, &array);
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(dict, &entry);
+}
+
 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
 {
        DBusMessageIter dict;
-       const char *type = "passive";
+       const char *type_active = "active";
+       const char *type_passive = "passive";
+       struct interface_scan_data *data = user_data;
 
        supplicant_dbus_dict_open(iter, &dict);
 
-       supplicant_dbus_dict_append_basic(&dict, "Type",
-                                               DBUS_TYPE_STRING, &type);
+       if (data && data->scan_params && data->scan_params->num_ssids > 0) {
+
+               supplicant_dbus_dict_append_basic(&dict, "Type",
+                                       DBUS_TYPE_STRING, &type_active);
+
+               supplicant_dbus_dict_append_array(&dict, "SSIDs",
+                                               DBUS_TYPE_STRING,
+                                               append_ssids,
+                                               data->scan_params);
+
+               supplicant_add_scan_frequency(&dict, "Channels",
+                                               add_scan_frequencies,
+                                               data->scan_params);
+       } else
+               supplicant_dbus_dict_append_basic(&dict, "Type",
+                                       DBUS_TYPE_STRING, &type_passive);
 
        supplicant_dbus_dict_close(iter, &dict);
 }
 
 int g_supplicant_interface_scan(GSupplicantInterface *interface,
+                               GSupplicantScanParams *scan_data,
                                GSupplicantInterfaceCallback callback,
                                                        void *user_data)
 {
-       struct interface_data *data;
+       struct interface_scan_data *data;
+       int ret;
 
        if (interface == NULL)
                return -EINVAL;
@@ -2415,10 +2541,16 @@ int g_supplicant_interface_scan(GSupplicantInterface 
*interface,
        data->interface = interface;
        data->callback = callback;
        data->user_data = user_data;
+       data->scan_params = scan_data;
 
-       return supplicant_dbus_method_call(interface->path,
+       ret = supplicant_dbus_method_call(interface->path,
                        SUPPLICANT_INTERFACE ".Interface", "Scan",
                        interface_scan_params, interface_scan_result, data);
+
+       if (ret < 0)
+               dbus_free(data);
+
+       return ret;
 }
 
 static int parse_supplicant_error(DBusMessageIter *iter)
diff --git a/plugins/wifi.c b/plugins/wifi.c
index e443f63..172fadb 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -256,21 +257,232 @@ static void scan_callback(int result, 
GSupplicantInterface *interface,
                connman_device_set_scanning(device, FALSE);
 }
 
+static int add_scan_param(GKeyFile *keyfile, const char* group,
+                       int freq, GSupplicantScanParams *scan_data)
+{
+       gchar *hex_ssid;
+       unsigned int i;
+
+       hex_ssid = g_key_file_get_string(keyfile, group,
+                                               "SSID", NULL);
+
+       if (hex_ssid != NULL) {
+               gchar *ssid;
+               unsigned int j = 0, hex;
+               size_t hex_ssid_len = strlen(hex_ssid);
+
+               ssid = g_try_malloc0(hex_ssid_len / 2);
+               if (ssid == NULL) {
+                       g_free(hex_ssid);
+                       return -ENOMEM;
+               }
+
+               for (i = 0; i < hex_ssid_len; i += 2) {
+                       sscanf(hex_ssid + i, "%02x", &hex);
+                       ssid[j++] = hex;
+               }
+
+               scan_data->ssids[scan_data->num_ssids].ssid = (void *)ssid;
+               scan_data->ssids[scan_data->num_ssids].ssid_len = j;
+               scan_data->num_ssids++;
+       }
+
+       g_free(hex_ssid);
+
+       /* dont add duplicate entries */
+       for (i = 0; i < G_SUPPLICANT_MAX_FAST_SCAN; i++) {
+               if (scan_data->freqs[i] == 0) {
+                       scan_data->freqs[i] = freq;
+                       break;
+               } else if (scan_data->freqs[i] == freq)
+                       break;
+       }
+
+       return 0;
+}
+
+struct last_connected {
+       struct ssid_entries {
+               const char *group;
+               GTimeVal modified ;
+               int freq;
+       } ssids[G_SUPPLICANT_MAX_FAST_SCAN];
+
+       int num_ssids;
+};
+
+static inline connman_bool_t g_timercmp(GTimeVal *a, GTimeVal *b)
+{
+       if (a->tv_sec == b->tv_sec) {
+               if (a->tv_usec < b->tv_usec)
+                       return TRUE;
+               else
+                       return FALSE;
+       } else if (a->tv_sec < (b)->tv_sec)
+               return TRUE;
+
+       return FALSE;
+}
+
+static inline void g_timerset(GTimeVal *a, GTimeVal *b)
+{
+
+       a->tv_sec = b->tv_sec;
+       a->tv_usec = b->tv_usec;
+}
+
+static void add_conn_list(struct last_connected *latest_list,
+                       const char *group, int freq, GTimeVal *modified)
+{
+       GTimeVal *old_conn;
+       int i, index = -1;
+
+       if (latest_list->num_ssids < G_SUPPLICANT_MAX_FAST_SCAN) {
+               index = latest_list->num_ssids;
+
+               latest_list->ssids[index].group = group;
+               g_timerset(&latest_list->ssids[index].modified, modified);
+               latest_list->ssids[index].freq = freq;
+
+               latest_list->num_ssids++;
+
+               return;
+       }
+
+       old_conn = modified;
+
+       for (i = 0; i < latest_list->num_ssids; i++) {
+               if (g_timercmp(&latest_list->ssids[i].modified, old_conn)) {
+                       index = i;
+                       old_conn = &latest_list->ssids[i].modified;
+               }
+       }
+
+       if (index != -1) {
+               latest_list->ssids[index].group = group;
+               g_timerset(&latest_list->ssids[index].modified, modified);
+               latest_list->ssids[index].freq = freq;
+       }
+}
+
+static int get_latest_connections(const char *prefix,
+                               GSupplicantScanParams *scan_data)
+{
+       struct last_connected latest_list;
+       GKeyFile *keyfile;
+       gchar *pathname, *data = NULL;
+       gsize length;
+       char **groups;
+       gchar *str = NULL;
+       int i;
+       int freq;
+       GTimeVal modified;
+
+       memset(&latest_list, 0, sizeof(latest_list));
+
+       pathname = g_strdup_printf("%s/default.profile", STORAGEDIR);
+       if (pathname == NULL)
+               return -ENOMEM;
+
+       keyfile = g_key_file_new();
+
+       if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
+               g_free(pathname);
+               return -ENOENT;
+       }
+
+       g_free(pathname);
+
+       if (g_key_file_load_from_data(keyfile, data, length,
+                                                       0, NULL) == FALSE) {
+               g_free(data);
+               return -EILSEQ;
+       }
+
+       g_free(data);
+
+       groups = g_key_file_get_groups(keyfile, &length);
+       for (i = 0; groups[i] != NULL; i++) {
+
+               if (g_str_has_prefix(groups[i], prefix) == TRUE) {
+                       str = g_key_file_get_string(keyfile,
+                                       groups[i], "Favorite", NULL);
+                       if (str == NULL || g_strcmp0(str, "true")) {
+                               if (str)
+                                       g_free(str);
+                               continue;
+                       }
+                       g_free(str);
+
+                       str = g_key_file_get_string(keyfile,
+                               groups[i], "AutoConnect", NULL);
+                       if (str == NULL || g_strcmp0(str, "true")) {
+                               if (str)
+                                       g_free(str);
+                               continue;
+                       }
+                       g_free(str);
+
+                       str = g_key_file_get_string(keyfile,
+                                       groups[i], "Modified", NULL);
+                       if (str != NULL) {
+                               g_time_val_from_iso8601(str, &modified);
+                               g_free(str);
+                       }
+
+                       freq = 0;
+                       freq = g_key_file_get_integer(keyfile, groups[i],
+                                                       "Frequency", NULL);
+
+                       if (freq)
+                               add_conn_list(&latest_list, groups[i],
+                                                       freq, &modified);
+               }
+       }
+
+       for (i = 0; i < latest_list.num_ssids; i++)
+               add_scan_param(keyfile, latest_list.ssids[i].group,
+                               latest_list.ssids[i].freq, scan_data);
+
+       g_strfreev(groups);
+
+       g_key_file_free(keyfile);
+
+       return 0;
+}
+
 static int wifi_scan(struct connman_device *device,
                        enum connman_device_scan_type type)
 {
        struct wifi_data *wifi = connman_device_get_data(device);
+       GSupplicantScanParams *scan_params = NULL;
        int ret;
+       int i;
 
        DBG("device %p %p", device, wifi->interface);
 
        if (wifi->tethering == TRUE)
                return 0;
 
-       ret = g_supplicant_interface_scan(wifi->interface, scan_callback,
-                                                               device);
+       if (type ==  CONNMAN_DEVICE_SCAN_TYPE_FAST) {
+               scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
+               if (scan_params == NULL)
+                       return -ENOMEM;
+
+               get_latest_connections("wifi_", scan_params);
+       }
+
+       ret = g_supplicant_interface_scan(wifi->interface,
+                                               scan_params,
+                                       scan_callback, device);
        if (ret == 0)
                connman_device_set_scanning(device, TRUE);
+       else if (scan_params) {
+               for (i = 0; i < scan_params->num_ssids; i++)
+                       g_free(scan_params->ssids[i].ssid);
+
+               g_free(scan_params);
+       }
 
        return ret;
 }
-- 
1.7.2.2

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

Reply via email to