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