unsigned int ssid_len;
char *identity;
char *passphrase;
+ gpointer user_data;
};
/**
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);
+ if (wifi == NULL)
+ return;
+
DBG("index %d flags %d change %d", wifi->index, flags, change);
if (!change)
wifi->networks = NULL;
}
-static void stop_autoscan(struct connman_device *device)
+static void reset_autoscan(struct connman_device *device)
{
struct wifi_data *wifi = connman_device_get_data(device);
struct autoscan_params *autoscan;
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);
if (wifi == NULL)
return;
- stop_autoscan(device);
-
iface_list = g_list_remove(iface_list, wifi);
remove_networks(device, wifi);
return 0;
}
+static int get_hidden_connections(int max_ssids,
+ GSupplicantScanParams *scan_data)
+{
+ GKeyFile *keyfile;
+ gchar **services;
+ char *ssid;
+ gchar *str;
+ int i, freq;
+ gboolean value;
+ int num_ssids = 0, add_param_failed = 0;
+
+ services = connman_storage_get_services();
+ for (i = 0; services && services[i]; i++) {
+ if (strncmp(services[i], "wifi_", 5) != 0)
+ continue;
+
+ keyfile = connman_storage_load_service(services[i]);
+
+ 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;
+ }
+
+ value = g_key_file_get_boolean(keyfile,
+ services[i], "AutoConnect", 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);
+
+ if (add_scan_param(ssid, freq, scan_data, max_ssids) < 0) {
+ str = g_key_file_get_string(keyfile,
+ services[i], "Name", NULL);
+ DBG("Cannot scan %s (%s)", ssid, str);
+ g_free(str);
+ add_param_failed++;
+ }
+
+ num_ssids++;
+
+ g_key_file_free(keyfile);
+ }
+
+ if (add_param_failed > 0)
+ connman_warn("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 throw_wifi_scan(struct connman_device *device,
GSupplicantInterfaceCallback callback)
{
struct wifi_data *wifi = connman_device_get_data(device);
int ret;
+ if (wifi == NULL)
+ return -ENODEV;
+
DBG("device %p %p", device, wifi->interface);
if (wifi->tethering == TRUE)
return 0;
+ if (connman_device_get_scanning(device) == TRUE)
+ return -EALREADY;
+
connman_device_ref(device);
ret = g_supplicant_interface_scan(wifi->interface, NULL,
return ret;
}
-static void autoscan_scan_callback(int result,
- GSupplicantInterface *interface, void *user_data)
+static void hidden_free(struct hidden_params *hidden)
+{
+ if (hidden == NULL)
+ return;
+
+ g_free(hidden->identity);
+ g_free(hidden->passphrase);
+ g_free(hidden);
+}
+
+static void scan_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
{
struct connman_device *device = user_data;
+ struct wifi_data *wifi = connman_device_get_data(device);
- DBG("");
+ 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;
+ }
+
+ if (result < 0)
+ connman_device_reset_scanning(device);
connman_device_set_scanning(device, FALSE);
+ start_autoscan(device);
connman_device_unref(device);
}
+static void scan_callback_hidden(int result,
+ GSupplicantInterface *interface, void *user_data)
+{
+ struct connman_device *device = user_data;
+ struct wifi_data *wifi = connman_device_get_data(device);
+ int driver_max_ssids;
+
+ DBG("result %d wifi %p", result, wifi);
+
+ if (wifi == NULL)
+ goto out;
+
+ /*
+ * Scan hidden networks so that we can autoconnect to them.
+ */
+ driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
+ wifi->interface);
+ DBG("max ssids %d", driver_max_ssids);
+
+ if (driver_max_ssids > 0) {
+ GSupplicantScanParams *scan_params;
+ int ret;
+
+ 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;
+ }
+
+ 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 autoscan_params *autoscan;
int interval;
+ if (wifi == NULL)
+ return FALSE;
+
autoscan = wifi->autoscan;
if (autoscan->interval <= 0) {
if (autoscan->interval >= autoscan->limit)
interval = autoscan->limit;
- throw_wifi_scan(wifi->device, autoscan_scan_callback);
+ throw_wifi_scan(wifi->device, scan_callback_hidden);
set_interval:
DBG("interval %d", interval);
DBG("device %p %p", device, wifi);
+ if (wifi == NULL)
+ return -ENODEV;
+
ret = g_supplicant_interface_create(interface, driver, NULL,
interface_create_callback,
wifi);
struct wifi_data *wifi = connman_device_get_data(device);
int ret;
- DBG("device %p", device);
+ 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);
return -EINPROGRESS;
}
-static void hidden_free(struct hidden_params *hidden)
-{
- if (hidden == NULL)
- return;
-
- g_free(hidden->identity);
- g_free(hidden->passphrase);
- g_free(hidden);
-}
-
-static void scan_callback(int result, GSupplicantInterface *interface,
- void *user_data)
-{
- struct connman_device *device = user_data;
- struct wifi_data *wifi = connman_device_get_data(device);
-
- DBG("result %d", result);
-
- if (wifi != NULL && wifi->hidden != NULL) {
- hidden_free(wifi->hidden);
- wifi->hidden = NULL;
- }
-
- if (result < 0)
- connman_device_reset_scanning(device);
-
- connman_device_set_scanning(device, FALSE);
- connman_device_unref(device);
-
- start_autoscan(device);
-}
-
struct last_connected {
GTimeVal modified;
gchar *ssid;
static int wifi_scan(struct connman_device *device)
{
- stop_autoscan(device);
+ reset_autoscan(device);
- return throw_wifi_scan(device, scan_callback);
+ return throw_wifi_scan(device, scan_callback_hidden);
}
static int wifi_scan_fast(struct connman_device *device)
int ret;
int driver_max_ssids = 0;
+ if (wifi == NULL)
+ return -ENODEV;
+
DBG("device %p %p", device, wifi->interface);
if (wifi->tethering == TRUE)
return 0;
+ if (connman_device_get_scanning(device) == TRUE)
+ return -EALREADY;
+
driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
wifi->interface);
DBG("max ssids %d", driver_max_ssids);
return wifi_scan(device);
}
- stop_autoscan(device);
-
connman_device_ref(device);
+ reset_autoscan(device);
+
ret = g_supplicant_interface_scan(wifi->interface, scan_params,
scan_callback, device);
if (ret == 0)
return ret;
}
+/*
+ * This func is only used when connecting to this specific AP first time.
+ * It is not used when system autoconnects to hidden AP.
+ */
static int wifi_scan_hidden(struct connman_device *device,
const char *ssid, unsigned int ssid_len,
- const char *identity, const char* passphrase)
+ const char *identity, const char* passphrase,
+ gpointer user_data)
{
struct wifi_data *wifi = connman_device_get_data(device);
GSupplicantScanParams *scan_params = NULL;
struct hidden_params *hidden;
int ret;
+ if (wifi == NULL)
+ return -ENODEV;
+
DBG("hidden SSID %s", ssid);
if (wifi->tethering == TRUE || wifi->hidden != NULL)
if (ssid == NULL || ssid_len == 0 || ssid_len > 32)
return -EINVAL;
+ if (connman_device_get_scanning(device) == TRUE)
+ return -EALREADY;
+
scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
if (scan_params == NULL)
return -ENOMEM;
hidden->ssid_len = ssid_len;
hidden->identity = g_strdup(identity);
hidden->passphrase = g_strdup(passphrase);
+ hidden->user_data = user_data;
wifi->hidden = hidden;
- stop_autoscan(device);
-
connman_device_ref(device);
+
+ reset_autoscan(device);
+
ret = g_supplicant_interface_scan(wifi->interface, scan_params,
scan_callback, device);
if (ret == 0)
connman_network_set_connected(network, FALSE);
connman_network_set_associating(network, FALSE);
+ wifi->disconnecting = FALSE;
start_autoscan(device);
return;
if (wifi == NULL || wifi->device == NULL) {
- connman_error("Wrong wifi pointer");
+ DBG("wifi interface already removed");
return;
}
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;
}