*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
*
* 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
#include <connman/device.h>
#include <connman/rtnl.h>
#include <connman/technology.h>
+#include <connman/service.h>
#include <connman/log.h>
#include <connman/option.h>
#include <connman/storage.h>
+#include <include/setting.h>
+#include <connman/provision.h>
#include <gsupplicant/gsupplicant.h>
#define CLEANUP_TIMEOUT 8 /* in seconds */
#define INACTIVE_TIMEOUT 12 /* in seconds */
-#define MAXIMUM_RETRIES 4
+#define MAXIMUM_RETRIES 2
+#define FAVORITE_MAXIMUM_RETRIES 4
#define BGSCAN_DEFAULT "simple:30:-45:300"
+#define AUTOSCAN_DEFAULT "exponential:3:300"
-struct connman_technology *wifi_technology = NULL;
+static struct connman_technology *wifi_technology = NULL;
struct hidden_params {
char ssid[32];
unsigned int ssid_len;
char *identity;
char *passphrase;
+ gpointer user_data;
+};
+
+/**
+ * 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 {
unsigned int watch;
int retries;
struct hidden_params *hidden;
+ /**
+ * autoscan "emulation".
+ */
+ struct autoscan_params *autoscan;
};
static GList *iface_list = NULL;
+static void start_autoscan(struct connman_device *device);
+
static void handle_tethering(struct wifi_data *wifi)
{
if (wifi->tethering == FALSE)
struct connman_device *device = user_data;
struct wifi_data *wifi = connman_device_get_data(device);
- DBG("index %d flags %d change %d", wifi->index, flags, change);
-
- if (!change)
+ if (wifi == NULL)
return;
+ DBG("index %d flags %d change %d", wifi->index, flags, change);
+
if ((wifi->flags & IFF_UP) != (flags & IFF_UP)) {
if (flags & IFF_UP)
DBG("interface up");
wifi->networks = NULL;
}
+static void reset_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 && autoscan->interval == 0)
+ return;
+
+ g_source_remove(autoscan->timeout);
+
+ autoscan->timeout = 0;
+ autoscan->interval = 0;
+
+ connman_device_unref(device);
+}
+
+static void stop_autoscan(struct connman_device *device)
+{
+ reset_autoscan(device);
+
+ connman_device_set_scanning(device, FALSE);
+}
+
static void wifi_remove(struct connman_device *device)
{
struct wifi_data *wifi = connman_device_get_data(device);
g_supplicant_interface_set_data(wifi->interface, NULL);
+ g_free(wifi->autoscan);
g_free(wifi->identifier);
g_free(wifi);
}
-static void interface_create_callback(int result,
- GSupplicantInterface *interface,
- void *user_data)
+static gboolean is_duplicate(GSList *list, gchar *ssid, int ssid_len)
{
- struct wifi_data *wifi = user_data;
+ GSList *iter;
- DBG("result %d ifname %s, wifi %p", result,
- g_supplicant_interface_get_ifname(interface),
- wifi);
+ for (iter = list; iter != NULL; iter = g_slist_next(iter)) {
+ struct scan_ssid *scan_ssid = iter->data;
- if (result < 0 || wifi == NULL)
- return;
+ if (ssid_len == scan_ssid->ssid_len &&
+ memcmp(ssid, scan_ssid->ssid, ssid_len) == 0)
+ return TRUE;
+ }
- wifi->interface = interface;
- g_supplicant_interface_set_data(interface, wifi);
+ return FALSE;
+}
- if (g_supplicant_interface_get_ready(interface) == FALSE)
- return;
+static int add_scan_param(gchar *hex_ssid, char *raw_ssid, int ssid_len,
+ int freq, GSupplicantScanParams *scan_data,
+ int driver_max_scan_ssids, char *ssid_name)
+{
+ unsigned int i;
+ struct scan_ssid *scan_ssid;
- DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
+ if (driver_max_scan_ssids > scan_data->num_ssids &&
+ (hex_ssid != NULL || raw_ssid != NULL)) {
+ gchar *ssid;
+ unsigned int j = 0, hex;
- if (wifi->device == NULL) {
- connman_error("WiFi device not set");
- return;
+ if (hex_ssid != NULL) {
+ size_t hex_ssid_len = strlen(hex_ssid);
+
+ ssid = g_try_malloc0(hex_ssid_len / 2);
+ if (ssid == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < hex_ssid_len; i += 2) {
+ sscanf(hex_ssid + i, "%02x", &hex);
+ ssid[j++] = hex;
+ }
+ } else {
+ ssid = raw_ssid;
+ j = ssid_len;
+ }
+
+ /*
+ * If we have already added hidden AP to the list,
+ * then do not do it again. This might happen if you have
+ * used or are using multiple wifi cards, so in that case
+ * you might have multiple service files for same AP.
+ */
+ if (is_duplicate(scan_data->ssids, ssid, j) == TRUE)
+ return 0;
+
+ scan_ssid = g_try_new(struct scan_ssid, 1);
+ if (scan_ssid == NULL) {
+ g_free(ssid);
+ return -ENOMEM;
+ }
+
+ memcpy(scan_ssid->ssid, ssid, j);
+ scan_ssid->ssid_len = j;
+ scan_data->ssids = g_slist_prepend(scan_data->ssids,
+ scan_ssid);
+
+ scan_data->num_ssids++;
+
+ DBG("SSID %s added to scanned list of %d entries", ssid_name,
+ scan_data->num_ssids);
+
+ if (hex_ssid != NULL)
+ g_free(ssid);
+ } else
+ return -EINVAL;
+
+ scan_data->ssids = g_slist_reverse(scan_data->ssids);
+
+ if (scan_data->freqs == NULL) {
+ scan_data->freqs = g_try_malloc0(sizeof(uint16_t) *
+ scan_data->num_ssids);
+ if (scan_data->freqs == NULL) {
+ g_slist_free_full(scan_data->ssids, g_free);
+ return -ENOMEM;
+ }
+ } else {
+ scan_data->freqs = g_try_realloc(scan_data->freqs,
+ sizeof(uint16_t) * scan_data->num_ssids);
+ if (scan_data->freqs == NULL) {
+ g_slist_free_full(scan_data->ssids, g_free);
+ return -ENOMEM;
+ }
+ scan_data->freqs[scan_data->num_ssids - 1] = 0;
}
- connman_device_set_powered(wifi->device, TRUE);
+ /* Don't add duplicate entries */
+ for (i = 0; i < scan_data->num_ssids; i++) {
+ if (scan_data->freqs[i] == 0) {
+ scan_data->freqs[i] = freq;
+ break;
+ } else if (scan_data->freqs[i] == freq)
+ break;
+ }
+
+ return 1;
}
-static int wifi_enable(struct connman_device *device)
+static int get_hidden_connections(int max_ssids,
+ GSupplicantScanParams *scan_data)
{
- struct wifi_data *wifi = connman_device_get_data(device);
- const char *interface = connman_device_get_string(device, "Interface");
- const char *driver = connman_option_get_string("wifi");
- int ret;
+ struct connman_config_entry **entries;
+ GKeyFile *keyfile;
+ gchar **services;
+ char *ssid, *name;
+ int i, freq, ret;
+ gboolean value;
+ int num_ssids = 0, add_param_failed = 0;
- DBG("device %p %p", device, wifi);
+ services = connman_storage_get_services();
+ for (i = 0; services && services[i]; i++) {
+ if (strncmp(services[i], "wifi_", 5) != 0)
+ continue;
- ret = g_supplicant_interface_create(interface, driver, NULL,
- interface_create_callback,
- wifi);
- if (ret < 0)
- return ret;
+ keyfile = connman_storage_load_service(services[i]);
+ if (keyfile == NULL)
+ continue;
- return -EINPROGRESS;
+ value = g_key_file_get_boolean(keyfile,
+ services[i], "Hidden", NULL);
+ if (value == FALSE) {
+ g_key_file_free(keyfile);
+ continue;
+ }
+
+ value = g_key_file_get_boolean(keyfile,
+ services[i], "Favorite", NULL);
+ if (value == FALSE) {
+ g_key_file_free(keyfile);
+ continue;
+ }
+
+ ssid = g_key_file_get_string(keyfile,
+ services[i], "SSID", NULL);
+
+ freq = g_key_file_get_integer(keyfile, services[i],
+ "Frequency", NULL);
+
+ name = g_key_file_get_string(keyfile, services[i], "Name",
+ NULL);
+
+ ret = add_scan_param(ssid, NULL, 0, freq, scan_data,
+ max_ssids, name);
+ if (ret < 0)
+ add_param_failed++;
+ else if (ret > 0)
+ num_ssids++;
+
+ g_free(name);
+ g_key_file_free(keyfile);
+ }
+
+ /*
+ * Check if there are any hidden AP that needs to be provisioned.
+ */
+ entries = connman_config_get_entries("wifi");
+ for (i = 0; entries && entries[i]; i++) {
+ int len;
+
+ if (entries[i]->hidden == FALSE)
+ continue;
+
+ if (entries[i]->ssid == NULL) {
+ ssid = entries[i]->name;
+ len = strlen(ssid);
+ } else {
+ ssid = entries[i]->ssid;
+ len = entries[i]->ssid_len;
+ }
+
+ if (ssid == NULL)
+ continue;
+
+ ret = add_scan_param(NULL, ssid, len, 0, scan_data,
+ max_ssids, ssid);
+ if (ret < 0)
+ add_param_failed++;
+ else if (ret > 0)
+ num_ssids++;
+ }
+
+ connman_config_free_entries(entries);
+
+ if (add_param_failed > 0)
+ DBG("Unable to scan %d out of %d SSIDs (max is %d)",
+ add_param_failed, num_ssids, max_ssids);
+
+ g_strfreev(services);
+
+ return num_ssids > max_ssids ? max_ssids : num_ssids;
}
-static int wifi_disable(struct connman_device *device)
+static int throw_wifi_scan(struct connman_device *device,
+ GSupplicantInterfaceCallback callback)
{
struct wifi_data *wifi = connman_device_get_data(device);
int ret;
- DBG("device %p", device);
+ if (wifi == NULL)
+ return -ENODEV;
- wifi->connected = FALSE;
- wifi->disconnecting = FALSE;
+ DBG("device %p %p", device, wifi->interface);
- if (wifi->pending_network != NULL)
- wifi->pending_network = NULL;
+ if (wifi->tethering == TRUE)
+ return -EBUSY;
- remove_networks(device, wifi);
+ if (connman_device_get_scanning(device) == TRUE)
+ return -EALREADY;
- ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL);
- if (ret < 0)
- return ret;
+ connman_device_ref(device);
- return -EINPROGRESS;
+ 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 hidden_free(struct hidden_params *hidden)
struct connman_device *device = user_data;
struct wifi_data *wifi = connman_device_get_data(device);
- DBG("result %d", result);
+ DBG("result %d wifi %p", result, wifi);
if (wifi != NULL && wifi->hidden != NULL) {
+ connman_network_clear_hidden(wifi->hidden->user_data);
hidden_free(wifi->hidden);
wifi->hidden = NULL;
}
connman_device_reset_scanning(device);
connman_device_set_scanning(device, FALSE);
+
+ if (result != -ENOLINK)
+ start_autoscan(device);
+
connman_device_unref(device);
}
-static int add_scan_param(gchar *hex_ssid, int freq,
- GSupplicantScanParams *scan_data,
- int driver_max_scan_ssids)
+static void scan_callback_hidden(int result,
+ GSupplicantInterface *interface, void *user_data)
{
- unsigned int i;
+ struct connman_device *device = user_data;
+ struct wifi_data *wifi = connman_device_get_data(device);
+ GSupplicantScanParams *scan_params;
+ int driver_max_ssids, ret;
- if (driver_max_scan_ssids > scan_data->num_ssids && hex_ssid != NULL) {
- gchar *ssid;
- unsigned int j = 0, hex;
- size_t hex_ssid_len = strlen(hex_ssid);
+ DBG("result %d wifi %p", result, wifi);
- ssid = g_try_malloc0(hex_ssid_len / 2);
- if (ssid == NULL)
- return -ENOMEM;
+ if (wifi == NULL)
+ goto out;
- for (i = 0; i < hex_ssid_len; i += 2) {
- sscanf(hex_ssid + i, "%02x", &hex);
- ssid[j++] = hex;
- }
+ /*
+ * Scan hidden networks so that we can autoconnect to them.
+ * We will assume 1 as a default number of ssid to scan.
+ */
+ driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
+ wifi->interface);
+ if (driver_max_ssids == 0)
+ driver_max_ssids = 1;
- memcpy(scan_data->ssids[scan_data->num_ssids].ssid, ssid, j);
- scan_data->ssids[scan_data->num_ssids].ssid_len = j;
- scan_data->num_ssids++;
+ DBG("max ssids %d", driver_max_ssids);
- g_free(ssid);
+ scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
+ if (scan_params == NULL)
+ goto out;
+
+ if (get_hidden_connections(driver_max_ssids, scan_params) > 0) {
+ ret = g_supplicant_interface_scan(wifi->interface,
+ scan_params,
+ scan_callback,
+ device);
+ if (ret == 0)
+ return;
}
- /* Don't 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;
+ g_supplicant_free_scan_params(scan_params);
+
+out:
+ scan_callback(result, interface, user_data);
+}
+
+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;
+
+ if (wifi == NULL)
+ return FALSE;
+
+ autoscan = wifi->autoscan;
+
+ if (autoscan->interval <= 0) {
+ interval = autoscan->base;
+ goto set_interval;
+ } else
+ interval = autoscan->interval * autoscan->base;
+
+ if (autoscan->interval >= autoscan->limit)
+ interval = autoscan->limit;
+
+ throw_wifi_scan(wifi->device, scan_callback_hidden);
+
+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;
}
- return 0;
+ 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)
+{
+ struct wifi_data *wifi = user_data;
+
+ if (result < 0) {
+ DBG("Could not enable Autoscan, falling back...");
+ setup_autoscan(wifi);
+ }
+}
+
+static void interface_create_callback(int result,
+ GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_data *wifi = user_data;
+
+ DBG("result %d ifname %s, wifi %p", result,
+ g_supplicant_interface_get_ifname(interface),
+ wifi);
+
+ if (result < 0 || wifi == NULL)
+ return;
+
+ wifi->interface = interface;
+ g_supplicant_interface_set_data(interface, wifi);
+
+ if (g_supplicant_interface_get_ready(interface) == FALSE)
+ return;
+
+ DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
+
+ if (wifi->device == NULL) {
+ connman_error("WiFi device not set");
+ return;
+ }
+
+ connman_device_set_powered(wifi->device, TRUE);
+
+ if (connman_setting_get_bool("BackgroundScanning") == FALSE)
+ return;
+
+ /* Setting up automatic scanning */
+ if (g_supplicant_interface_autoscan(interface, AUTOSCAN_DEFAULT,
+ interface_autoscan_callback, wifi) < 0) {
+ DBG("Could not enable Autoscan, falling back...");
+ setup_autoscan(wifi);
+ }
+}
+
+static int wifi_enable(struct connman_device *device)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ const char *interface = connman_device_get_string(device, "Interface");
+ const char *driver = connman_option_get_string("wifi");
+ int ret;
+
+ DBG("device %p %p", device, wifi);
+
+ if (wifi == NULL)
+ return -ENODEV;
+
+ ret = g_supplicant_interface_create(interface, driver, NULL,
+ interface_create_callback,
+ wifi);
+ if (ret < 0)
+ return ret;
+
+ return -EINPROGRESS;
+}
+
+static int wifi_disable(struct connman_device *device)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ int ret;
+
+ DBG("device %p wifi %p", device, wifi);
+
+ if (wifi == NULL)
+ return -ENODEV;
+
+ wifi->connected = FALSE;
+ wifi->disconnecting = FALSE;
+
+ if (wifi->pending_network != NULL)
+ wifi->pending_network = NULL;
+
+ stop_autoscan(device);
+
+ /* In case of a user scan, device is still referenced */
+ if (connman_device_get_scanning(device) == TRUE) {
+ connman_device_set_scanning(device, FALSE);
+ connman_device_unref(wifi->device);
+ }
+
+ remove_networks(device, wifi);
+
+ ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return -EINPROGRESS;
}
struct last_connected {
continue;
keyfile = connman_storage_load_service(services[i]);
+ if (keyfile == NULL)
+ continue;
str = g_key_file_get_string(keyfile,
services[i], "Favorite", NULL);
g_strfreev(services);
- num_ssids = num_ssids > G_SUPPLICANT_MAX_FAST_SCAN ?
- G_SUPPLICANT_MAX_FAST_SCAN : num_ssids;
+ num_ssids = num_ssids > max_ssids ? max_ssids : num_ssids;
iter = g_sequence_get_begin_iter(latest_list);
DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
entry->modified.tv_sec);
- add_scan_param(entry->ssid, entry->freq, scan_data, max_ssids);
+ add_scan_param(entry->ssid, NULL, 0, entry->freq, scan_data,
+ max_ssids, entry->ssid);
iter = g_sequence_iter_next(iter);
}
return num_ssids;
}
-static int wifi_scan(struct connman_device *device)
+static int wifi_scan_simple(struct connman_device *device)
{
- struct wifi_data *wifi = connman_device_get_data(device);
- int ret;
-
- DBG("device %p %p", device, wifi->interface);
+ reset_autoscan(device);
- 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 throw_wifi_scan(device, scan_callback_hidden);
}
-static int wifi_scan_fast(struct connman_device *device)
+/*
+ * Note that the hidden scan is only used when connecting to this specific
+ * hidden AP first time. It is not used when system autoconnects to hidden AP.
+ */
+static int wifi_scan(struct connman_device *device,
+ const char *ssid, unsigned int ssid_len,
+ const char *identity, const char* passphrase,
+ gpointer user_data)
{
struct wifi_data *wifi = connman_device_get_data(device);
GSupplicantScanParams *scan_params = NULL;
+ struct scan_ssid *scan_ssid;
+ struct hidden_params *hidden;
int ret;
int driver_max_ssids = 0;
+ connman_bool_t do_hidden;
- DBG("device %p %p", device, wifi->interface);
+ if (wifi == NULL)
+ return -ENODEV;
+
+ DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid);
if (wifi->tethering == TRUE)
return 0;
- driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
+ if (connman_device_get_scanning(device) == TRUE)
+ return -EALREADY;
+
+ if (ssid == NULL || ssid_len == 0 || ssid_len > 32) {
+ do_hidden = FALSE;
+ } else {
+ if (wifi->hidden != NULL)
+ return -EBUSY;
+
+ do_hidden = TRUE;
+ }
+
+ if (do_hidden == FALSE) {
+ driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
wifi->interface);
- DBG("max ssids %d", driver_max_ssids);
- if (driver_max_ssids == 0)
- return wifi_scan(device);
+ DBG("max ssids %d", driver_max_ssids);
+ if (driver_max_ssids == 0)
+ return wifi_scan_simple(device);
+ }
scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
if (scan_params == NULL)
return -ENOMEM;
- ret = get_latest_connections(driver_max_ssids, scan_params);
- if (ret <= 0) {
- g_free(scan_params);
- return wifi_scan(device);
+ if (do_hidden == TRUE) {
+ scan_ssid = g_try_new(struct scan_ssid, 1);
+ if (scan_ssid == NULL) {
+ g_free(scan_params);
+ return -ENOMEM;
+ }
+
+ memcpy(scan_ssid->ssid, ssid, ssid_len);
+ scan_ssid->ssid_len = ssid_len;
+ scan_params->ssids = g_slist_prepend(scan_params->ssids,
+ scan_ssid);
+ scan_params->num_ssids = 1;
+
+ hidden = g_try_new0(struct hidden_params, 1);
+ if (hidden == NULL) {
+ g_free(scan_params);
+ return -ENOMEM;
+ }
+
+ memcpy(hidden->ssid, ssid, ssid_len);
+ hidden->ssid_len = ssid_len;
+ hidden->identity = g_strdup(identity);
+ hidden->passphrase = g_strdup(passphrase);
+ hidden->user_data = user_data;
+ wifi->hidden = hidden;
+
+ } else {
+ ret = get_latest_connections(driver_max_ssids, scan_params);
+ if (ret <= 0) {
+ g_supplicant_free_scan_params(scan_params);
+ return wifi_scan_simple(device);
+ }
}
connman_device_ref(device);
+
+ reset_autoscan(device);
+
ret = g_supplicant_interface_scan(wifi->interface, scan_params,
scan_callback, device);
if (ret == 0)
connman_device_set_scanning(device, TRUE);
else {
- g_free(scan_params);
+ g_supplicant_free_scan_params(scan_params);
connman_device_unref(device);
+
+ if (do_hidden == TRUE) {
+ hidden_free(wifi->hidden);
+ wifi->hidden = NULL;
+ }
}
return ret;
}
-static int wifi_scan_hidden(struct connman_device *device,
- const char *ssid, unsigned int ssid_len,
- const char *identity, const char* passphrase)
+static void wifi_regdom_callback(int result,
+ const char *alpha2,
+ void *user_data)
{
- struct wifi_data *wifi = connman_device_get_data(device);
- GSupplicantScanParams *scan_params = NULL;
- struct hidden_params *hidden;
- int ret;
-
- DBG("hidden SSID %s", ssid);
+ struct connman_device *device = user_data;
- if (wifi->tethering == TRUE || wifi->hidden != NULL)
- return -EBUSY;
+ connman_device_regdom_notify(device, result, alpha2);
- if (ssid == NULL || ssid_len == 0 || ssid_len > 32)
- return -EINVAL;
+ connman_device_unref(device);
+}
- scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
- if (scan_params == NULL)
- return -ENOMEM;
- memcpy(scan_params->ssids[0].ssid, ssid, ssid_len);
- scan_params->ssids[0].ssid_len = ssid_len;
- scan_params->num_ssids = 1;
+static int wifi_set_regdom(struct connman_device *device, const char *alpha2)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ int ret;
- hidden = g_try_new0(struct hidden_params, 1);
- if (hidden == NULL) {
- g_free(scan_params);
- return -ENOMEM;
- }
- memcpy(hidden->ssid, ssid, ssid_len);
- hidden->ssid_len = ssid_len;
- hidden->identity = g_strdup(identity);
- hidden->passphrase = g_strdup(passphrase);
- wifi->hidden = hidden;
+ if (wifi == NULL)
+ return -EINVAL;
connman_device_ref(device);
- ret = g_supplicant_interface_scan(wifi->interface, scan_params,
- scan_callback, device);
- if (ret == 0)
- connman_device_set_scanning(device, TRUE);
- else {
+
+ ret = g_supplicant_interface_set_country(wifi->interface,
+ wifi_regdom_callback,
+ alpha2, device);
+ if (ret != 0)
connman_device_unref(device);
- g_free(scan_params);
- hidden_free(wifi->hidden);
- wifi->hidden = NULL;
- }
return ret;
}
.enable = wifi_enable,
.disable = wifi_disable,
.scan = wifi_scan,
- .scan_fast = wifi_scan_fast,
- .scan_hidden = wifi_scan_hidden,
+ .set_regdom = wifi_set_regdom,
};
static void system_ready(void)
ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
- ssid->bgscan = BGSCAN_DEFAULT;
+ if (connman_setting_get_bool("BackgroundScanning") == TRUE)
+ ssid->bgscan = BGSCAN_DEFAULT;
}
static int network_connect(struct connman_network *network)
{
struct wifi_data *wifi = user_data;
+ DBG("result %d supplicant interface %p wifi %p",
+ result, interface, wifi);
+
+ if (result == -ECONNABORTED) {
+ DBG("wifi interface no longer available");
+ return;
+ }
+
if (wifi->network != NULL) {
/*
* if result < 0 supplican return an error because
wifi->pending_network = NULL;
}
+ start_autoscan(wifi->device);
}
static int network_disconnect(struct connman_network *network)
switch (wifi->state) {
case G_SUPPLICANT_STATE_UNKNOWN:
+ case G_SUPPLICANT_STATE_DISABLED:
case G_SUPPLICANT_STATE_DISCONNECTED:
case G_SUPPLICANT_STATE_INACTIVE:
case G_SUPPLICANT_STATE_SCANNING:
* actually means that we are idling. */
switch (wifi->state) {
case G_SUPPLICANT_STATE_UNKNOWN:
+ case G_SUPPLICANT_STATE_DISABLED:
case G_SUPPLICANT_STATE_DISCONNECTED:
case G_SUPPLICANT_STATE_INACTIVE:
case G_SUPPLICANT_STATE_SCANNING:
struct connman_network *network,
struct wifi_data *wifi)
{
+ struct connman_service *service;
+
if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
return FALSE;
+ service = connman_service_lookup_from_network(network);
+ if (service == NULL)
+ return FALSE;
+
wifi->retries++;
- if (wifi->retries < MAXIMUM_RETRIES)
+ if (connman_service_get_favorite(service) == TRUE) {
+ if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
+ return TRUE;
+ } else if (wifi->retries < MAXIMUM_RETRIES)
return TRUE;
connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
case G_SUPPLICANT_STATE_AUTHENTICATING:
case G_SUPPLICANT_STATE_ASSOCIATING:
- connman_network_set_associating(network, TRUE);
+ stop_autoscan(device);
+
+ if (wifi->connected == FALSE)
+ connman_network_set_associating(network, TRUE);
+
break;
case G_SUPPLICANT_STATE_COMPLETED:
+ /* though it should be already stopped: */
+ stop_autoscan(device);
+
if (handle_wps_completion(interface, network, device, wifi) ==
FALSE)
break;
- /* reset scan trigger and schedule background scan */
- connman_device_schedule_scan(device);
-
connman_network_set_connected(network, TRUE);
break;
FALSE) != 0)
DBG("Could not disables selected network");
- connman_network_set_associating(network, FALSE);
connman_network_set_connected(network, FALSE);
+ connman_network_set_associating(network, FALSE);
+ wifi->disconnecting = FALSE;
+
+ start_autoscan(device);
+
break;
case G_SUPPLICANT_STATE_INACTIVE:
connman_network_set_associating(network, FALSE);
+ start_autoscan(device);
+
break;
case G_SUPPLICANT_STATE_UNKNOWN:
+ case G_SUPPLICANT_STATE_DISABLED:
case G_SUPPLICANT_STATE_ASSOCIATED:
case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
wifi->state = state;
+ /* Saving wpa_s state policy:
+ * If connected and if the state changes are roaming related:
+ * --> We stay connected
+ * If completed
+ * --> We are connected
+ * All other case:
+ * --> We are not connected
+ * */
+ switch (state) {
+ case G_SUPPLICANT_STATE_AUTHENTICATING:
+ case G_SUPPLICANT_STATE_ASSOCIATING:
+ case G_SUPPLICANT_STATE_ASSOCIATED:
+ case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
+ case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
+ if (wifi->connected == TRUE)
+ connman_warn("Probably roaming right now!"
+ " Staying connected...");
+ else
+ wifi->connected = FALSE;
+ break;
+ case G_SUPPLICANT_STATE_COMPLETED:
+ wifi->connected = TRUE;
+ break;
+ default:
+ wifi->connected = FALSE;
+ break;
+ }
+
DBG("DONE");
}
return;
if (wifi == NULL || wifi->device == NULL) {
- connman_error("Wrong wifi pointer");
+ DBG("wifi interface already removed");
return;
}
return;
}
- wifi->networks = g_slist_append(wifi->networks, network);
+ wifi->networks = g_slist_prepend(wifi->networks, network);
}
if (name != NULL && name[0] != '\0')
if (ssid != NULL)
connman_network_set_group(network, group);
- if (wifi->hidden != NULL) {
+ if (wifi->hidden != NULL && ssid != NULL) {
if (wifi->hidden->ssid_len == ssid_len &&
memcmp(wifi->hidden->ssid, ssid,
ssid_len) == 0) {
connman_network_connect_hidden(network,
wifi->hidden->identity,
- wifi->hidden->passphrase);
+ wifi->hidden->passphrase,
+ wifi->hidden->user_data);
+ wifi->hidden->user_data = NULL;
hidden_free(wifi->hidden);
wifi->hidden = NULL;
}
return -EOPNOTSUPP;
}
-static void regdom_callback(void *user_data)
+static void regdom_callback(int result, const char *alpha2, void *user_data)
{
- char *alpha2 = user_data;
-
DBG("");
if (wifi_technology == NULL)
return;
+ if (result != 0)
+ alpha2 = NULL;
+
connman_technology_regdom_notify(wifi_technology, alpha2);
}
static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
{
- return g_supplicant_set_country(alpha2, regdom_callback, alpha2);
+ return g_supplicant_set_country(alpha2, regdom_callback, NULL);
}
static struct connman_technology_driver tech_driver = {