*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-2014 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 <errno.h>
#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <net/if.h>
#include "connman.h"
static gchar **device_filter = NULL;
static gchar **nodevice_filter = NULL;
+#if defined TIZEN_EXT
+static DBusConnection *connection;
+#endif
+
enum connman_pending_type {
PENDING_NONE = 0,
PENDING_ENABLE = 1,
};
struct connman_device {
- gint refcount;
+ int refcount;
enum connman_device_type type;
enum connman_pending_type powered_pending; /* Indicates a pending
- enable/disable request */
- connman_bool_t offlinemode;
- connman_bool_t blocked;
- connman_bool_t powered;
- connman_bool_t powered_persistent;
- connman_bool_t scanning;
- connman_bool_t disconnected;
- connman_bool_t reconnect;
- connman_uint16_t scan_interval;
- connman_uint16_t backoff_interval;
+ * enable/disable
+ * request
+ */
+ bool powered;
+ bool scanning[MAX_CONNMAN_SERVICE_TYPES];
char *name;
char *node;
char *address;
char *interface;
char *ident;
char *path;
- char *devname;
- int phyindex;
int index;
- unsigned int connections;
- guint scan_timeout;
guint pending_timeout;
struct connman_device_driver *driver;
char *last_network;
struct connman_network *network;
GHashTable *networks;
+#if defined TIZEN_EXT
+ time_t last_user_selection_time;
+ char *last_user_selection_ident;
+ char *last_connected_ident;
+ DBusMessage *pending_reply;
+ int max_scan_ssids;
+ bool is_5_0_ghz_supported;
+#endif
};
-#define SCAN_INITIAL_DELAY 10
-
-static gboolean device_scan_trigger(gpointer user_data)
-{
- struct connman_device *device = user_data;
-
- DBG("device %p", device);
-
- if (device->driver == NULL) {
- device->scan_timeout = 0;
- return FALSE;
- }
-
- if (device->driver->scan)
- device->driver->scan(device);
-
- return TRUE;
-}
-
-static void clear_scan_trigger(struct connman_device *device)
+static void clear_pending_trigger(struct connman_device *device)
{
- if (device->scan_timeout > 0) {
- g_source_remove(device->scan_timeout);
- device->scan_timeout = 0;
+#if defined TIZEN_EXT
+ if (device->pending_reply) {
+ dbus_message_unref(device->pending_reply);
+ device->pending_reply = NULL;
}
-}
-
-static void reset_scan_trigger(struct connman_device *device)
-{
- clear_scan_trigger(device);
-
- if (device->scan_interval > 0) {
- guint interval;
-
- if (g_hash_table_size(device->networks) == 0) {
- if (device->backoff_interval >= device->scan_interval)
- device->backoff_interval = SCAN_INITIAL_DELAY;
- interval = device->backoff_interval;
- } else
- interval = device->scan_interval;
-
- DBG("interval %d", interval);
-
- device->scan_timeout = g_timeout_add_seconds(interval,
- device_scan_trigger, device);
-
- device->backoff_interval *= 2;
- if (device->backoff_interval > device->scan_interval)
- device->backoff_interval = device->scan_interval;
+#endif
+ if (device->pending_timeout > 0) {
+ g_source_remove(device->pending_timeout);
+ device->pending_timeout = 0;
}
}
-static void force_scan_trigger(struct connman_device *device)
-{
- clear_scan_trigger(device);
-
- device->scan_timeout = g_timeout_add_seconds(5,
- device_scan_trigger, device);
-}
-
-void connman_device_schedule_scan(struct connman_device *device)
-{
- reset_scan_trigger(device);
-}
-
static const char *type2description(enum connman_device_type type)
{
switch (type) {
return "Ethernet";
case CONNMAN_DEVICE_TYPE_WIFI:
return "Wireless";
- case CONNMAN_DEVICE_TYPE_WIMAX:
- return "WiMAX";
case CONNMAN_DEVICE_TYPE_BLUETOOTH:
return "Bluetooth";
case CONNMAN_DEVICE_TYPE_GPS:
return "ethernet";
case CONNMAN_DEVICE_TYPE_WIFI:
return "wifi";
- case CONNMAN_DEVICE_TYPE_WIMAX:
- return "wimax";
case CONNMAN_DEVICE_TYPE_BLUETOOTH:
return "bluetooth";
case CONNMAN_DEVICE_TYPE_GPS:
return NULL;
}
-enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
+enum connman_service_type __connman_device_get_service_type(
+ struct connman_device *device)
{
enum connman_device_type type = connman_device_get_type(device);
return CONNMAN_SERVICE_TYPE_ETHERNET;
case CONNMAN_DEVICE_TYPE_WIFI:
return CONNMAN_SERVICE_TYPE_WIFI;
- case CONNMAN_DEVICE_TYPE_WIMAX:
- return CONNMAN_SERVICE_TYPE_WIMAX;
case CONNMAN_DEVICE_TYPE_BLUETOOTH:
return CONNMAN_SERVICE_TYPE_BLUETOOTH;
case CONNMAN_DEVICE_TYPE_CELLULAR:
return CONNMAN_SERVICE_TYPE_UNKNOWN;
}
+static bool device_has_service_type(struct connman_device *device,
+ enum connman_service_type service_type)
+{
+ enum connman_service_type device_service_type =
+ __connman_device_get_service_type(device);
+
+ /*
+ * For devices whose device_service_type is unknown we should
+ * allow to decide whether they support specific service_type
+ * by themself.
+ */
+ if (device_service_type == CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return true;
+
+#if defined TIZEN_EXT_WIFI_MESH
+ if (device_service_type == CONNMAN_SERVICE_TYPE_MESH)
+ return service_type != CONNMAN_SERVICE_TYPE_MESH;
+#endif
+
+ if (device_service_type == CONNMAN_SERVICE_TYPE_WIFI) {
+ return service_type == CONNMAN_SERVICE_TYPE_WIFI ||
+ service_type == CONNMAN_SERVICE_TYPE_P2P;
+ }
+
+ return service_type == device_service_type;
+}
+
static gboolean device_pending_reset(gpointer user_data)
{
struct connman_device *device = user_data;
DBG("device %p", device);
- /* Power request timedout, reset power pending state. */
- if (device->pending_timeout > 0) {
- g_source_remove(device->pending_timeout);
- device->pending_timeout = 0;
- device->powered_pending = PENDING_NONE;
+#if defined TIZEN_EXT
+ DBusMessage *reply;
+
+ /* Power request timed out, send ETIMEDOUT. */
+ if (device->pending_reply) {
+ reply = __connman_error_failed(device->pending_reply, ETIMEDOUT);
+ if (reply)
+ g_dbus_send_message(connection, reply);
+
+ dbus_message_unref(device->pending_reply);
+ device->pending_reply = NULL;
}
+#endif
+ /* Power request timedout, reset power pending state. */
+ device->pending_timeout = 0;
+ device->powered_pending = PENDING_NONE;
return FALSE;
}
{
int err;
- DBG("device %p %d", device, device->blocked);
+ DBG("device %p", device);
if (!device->driver || !device->driver->enable)
return -EOPNOTSUPP;
- if (device->blocked == TRUE)
- return -ENOLINK;
-
/* There is an ongoing power disable request. */
if (device->powered_pending == PENDING_DISABLE)
return -EBUSY;
if (device->powered_pending == PENDING_ENABLE)
- return -EALREADY;
+ return -EINPROGRESS;
- if (device->powered_pending == PENDING_NONE && device->powered == TRUE)
+ if (device->powered_pending == PENDING_NONE && device->powered)
return -EALREADY;
+ if (device->index > 0) {
+ err = connman_inet_ifup(device->index);
+ if (err < 0 && err != -EALREADY)
+ return err;
+ }
+
device->powered_pending = PENDING_ENABLE;
err = device->driver->enable(device);
* Invoke the callback
*/
if (err == 0) {
- connman_device_set_powered(device, TRUE);
+ connman_device_set_powered(device, true);
goto done;
}
if (err == -EALREADY) {
/* If device is already powered, but connman is not updated */
- connman_device_set_powered(device, TRUE);
+ connman_device_set_powered(device, true);
goto done;
}
/*
DBG("device %p", device);
- if (!device->driver || !device->driver->disable)
- return -EOPNOTSUPP;
-
- if (device->blocked == TRUE)
- return -ENOLINK;
-
/* Ongoing power enable request */
if (device->powered_pending == PENDING_ENABLE)
return -EBUSY;
if (device->powered_pending == PENDING_DISABLE)
- return -EALREADY;
+ return -EINPROGRESS;
- if (device->powered_pending == PENDING_NONE && device->powered == FALSE)
+ if (device->powered_pending == PENDING_NONE && !device->powered)
return -EALREADY;
- device->reconnect = FALSE;
+ device->powered_pending = PENDING_DISABLE;
- clear_scan_trigger(device);
+ if (device->network) {
+ struct connman_service *service =
+ connman_service_lookup_from_network(device->network);
- err = device->driver->disable(device);
- if (err == 0) {
- connman_device_set_powered(device, FALSE);
- goto done;
+ if (service)
+ __connman_service_disconnect(service);
+ else
+ connman_network_set_connected(device->network, false);
}
- if (err == -EALREADY) {
- connman_device_set_powered(device, FALSE);
+ if (!device->driver || !device->driver->disable)
+ return -EOPNOTSUPP;
+
+ err = device->driver->disable(device);
+ if (err == 0 || err == -EALREADY) {
+ connman_device_set_powered(device, false);
goto done;
}
return err;
}
-static int set_powered(struct connman_device *device, connman_bool_t powered)
-{
- DBG("device %p powered %d", device, powered);
-
- if (powered == TRUE)
- return __connman_device_enable(device);
- else
- return __connman_device_disable(device);
-}
-
-static int setup_device(struct connman_device *device)
-{
- DBG("device %p", device);
-
- __connman_technology_add_device(device);
-
- if (device->offlinemode == FALSE &&
- device->powered_persistent == TRUE)
- __connman_device_enable(device);
-
- return 0;
-}
-
static void probe_driver(struct connman_device_driver *driver)
{
GSList *list;
DBG("driver %p name %s", driver, driver->name);
- for (list = device_list; list != NULL; list = list->next) {
+ for (list = device_list; list; list = list->next) {
struct connman_device *device = list->data;
- if (device->driver != NULL)
+ if (device->driver)
continue;
if (driver->type != device->type)
device->driver = driver;
- setup_device(device);
+ __connman_technology_add_device(device);
}
}
DBG("driver %p name %s", driver, driver->name);
- for (list = device_list; list != NULL; list = list->next) {
+ for (list = device_list; list; list = list->next) {
struct connman_device *device = list->data;
if (device->driver == driver)
}
}
-connman_bool_t __connman_device_has_driver(struct connman_device *device)
+bool __connman_device_has_driver(struct connman_device *device)
{
- if (device == NULL || device->driver == NULL)
- return FALSE;
+ if (!device || !device->driver)
+ return false;
- return TRUE;
+ return true;
}
static GSList *driver_list = NULL;
{
DBG("device %p name %s", device, device->name);
- clear_scan_trigger(device);
+ clear_pending_trigger(device);
+
+ g_hash_table_destroy(device->networks);
+ device->networks = NULL;
g_free(device->ident);
g_free(device->node);
g_free(device->address);
g_free(device->interface);
g_free(device->path);
- g_free(device->devname);
g_free(device->last_network);
- g_hash_table_destroy(device->networks);
- device->networks = NULL;
+#if defined TIZEN_EXT
+ g_free(device->last_user_selection_ident);
+ g_free(device->last_connected_ident);
+#endif
g_free(device);
}
+#if defined TIZEN_EXT
+static void device_send_changed(const char *ifname, enum connman_service_type type,
+ const char *key, bool state)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, dict;
+ dbus_bool_t value = state;
+ const char *tech_path = connman_techonology_get_path(type);
+
+ if (!tech_path || !ifname)
+ return;
+
+ DBG("%s %s %s", ifname, key, state ? "TRUE" : "FALSE");
+
+ signal = dbus_message_new_signal(tech_path,
+ CONNMAN_TECHNOLOGY_INTERFACE, "DeviceChanged");
+ if (!signal)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+
+ connman_dbus_dict_open(&iter, &dict);
+ connman_dbus_dict_append_basic(&dict, "Ifname",
+ DBUS_TYPE_STRING,
+ &ifname);
+ connman_dbus_dict_append_basic(&dict, key,
+ DBUS_TYPE_BOOLEAN,
+ &value);
+ connman_dbus_dict_close(&iter, &dict);
+
+ dbus_connection_send(connection, signal, NULL);
+ dbus_message_unref(signal);
+}
+
+static void device_send_reply(struct connman_device *device)
+{
+ if (device->pending_reply) {
+ g_dbus_send_reply(connection,
+ device->pending_reply, DBUS_TYPE_INVALID);
+ dbus_message_unref(device->pending_reply);
+ device->pending_reply = NULL;
+ }
+}
+#endif
+
/**
* connman_device_create:
* @node: device node name (for example an address)
enum connman_device_type type)
{
struct connman_device *device;
- enum connman_service_type service_type;
- connman_bool_t bg_scan;
DBG("node %s type %d", node, type);
device = g_try_new0(struct connman_device, 1);
- if (device == NULL)
+ if (!device)
return NULL;
DBG("device %p", device);
device->refcount = 1;
- bg_scan = connman_setting_get_bool("BackgroundScanning");
-
device->type = type;
device->name = g_strdup(type2description(device->type));
- device->powered_persistent = TRUE;
-
- device->phyindex = -1;
-
- service_type = __connman_device_get_service_type(device);
- device->blocked = __connman_technology_get_blocked(service_type);
- device->backoff_interval = SCAN_INITIAL_DELAY;
-
- switch (type) {
- case CONNMAN_DEVICE_TYPE_UNKNOWN:
- case CONNMAN_DEVICE_TYPE_ETHERNET:
- case CONNMAN_DEVICE_TYPE_WIMAX:
- case CONNMAN_DEVICE_TYPE_BLUETOOTH:
- case CONNMAN_DEVICE_TYPE_CELLULAR:
- case CONNMAN_DEVICE_TYPE_GPS:
- case CONNMAN_DEVICE_TYPE_GADGET:
- case CONNMAN_DEVICE_TYPE_VENDOR:
- device->scan_interval = 0;
- break;
- case CONNMAN_DEVICE_TYPE_WIFI:
- if (bg_scan == TRUE)
- device->scan_interval = 300;
- else
- device->scan_interval = 0;
- break;
- }
-
device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, free_network);
- device_list = g_slist_append(device_list, device);
+ device_list = g_slist_prepend(device_list, device);
return device;
}
*
* Increase reference counter of device
*/
-struct connman_device *connman_device_ref(struct connman_device *device)
+struct connman_device *connman_device_ref_debug(struct connman_device *device,
+ const char *file, int line, const char *caller)
{
- DBG("%p", device);
+ DBG("%p ref %d by %s:%d:%s()", device, device->refcount + 1,
+ file, line, caller);
- g_atomic_int_inc(&device->refcount);
+ __sync_fetch_and_add(&device->refcount, 1);
return device;
}
*
* Decrease reference counter of device
*/
-void connman_device_unref(struct connman_device *device)
+void connman_device_unref_debug(struct connman_device *device,
+ const char *file, int line, const char *caller)
{
- if (g_atomic_int_dec_and_test(&device->refcount) == FALSE)
+ DBG("%p ref %d by %s:%d:%s()", device, device->refcount - 1,
+ file, line, caller);
+
+ if (__sync_fetch_and_sub(&device->refcount, 1) != 1)
return;
if (device->driver) {
return device->index;
}
-int __connman_device_get_phyindex(struct connman_device *device)
-{
- return device->phyindex;
-}
-
-void __connman_device_set_phyindex(struct connman_device *device,
- int phyindex)
-{
- device->phyindex = phyindex;
-}
-
/**
* connman_device_set_interface:
* @device: device structure
void connman_device_set_interface(struct connman_device *device,
const char *interface)
{
- g_free(device->devname);
- device->devname = g_strdup(interface);
-
g_free(device->interface);
device->interface = g_strdup(interface);
- if (device->name == NULL) {
+ if (!device->name) {
const char *str = type2description(device->type);
- if (str != NULL && device->interface != NULL)
+ if (str && device->interface)
device->name = g_strdup_printf("%s (%s)", str,
device->interface);
}
* Change power state of device
*/
int connman_device_set_powered(struct connman_device *device,
- connman_bool_t powered)
+ bool powered)
{
+ struct connman_device_scan_params params;
enum connman_service_type type;
+ int i;
- DBG("driver %p powered %d", device, powered);
+ DBG("device %p powered %d", device, powered);
if (device->powered == powered)
return -EALREADY;
- /* Reset pending request */
- g_source_remove(device->pending_timeout);
- device->pending_timeout = 0;
- device->powered_pending = PENDING_NONE;
+#if defined TIZEN_EXT
+ device_send_reply(device);
+#endif
- if (device->offlinemode == TRUE && powered == TRUE)
- return __connman_device_disable(device);
+ clear_pending_trigger(device);
+
+ device->powered_pending = PENDING_NONE;
device->powered = powered;
type = __connman_device_get_service_type(device);
- if (device->powered == TRUE)
- __connman_technology_enabled(type);
- else
- __connman_technology_disabled(type);
+#if defined TIZEN_EXT
+ device_send_changed(device->interface, type, "Powered", powered);
+ technology_save_device(device);
+#endif
- if (powered == FALSE) {
- device->connections = 0;
+ if (!device->powered) {
+ __connman_technology_disabled(type);
return 0;
}
- connman_device_set_disconnected(device, FALSE);
- device->scanning = FALSE;
+ __connman_technology_enabled(type);
+
+ for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
+ device->scanning[i] = false;
- reset_scan_trigger(device);
+ if (device->driver && device->driver->scan) {
+ memset(¶ms, 0, sizeof(params));
+ params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
- if (device->driver && device->driver->scan)
- device->driver->scan(device);
+ device->driver->scan(device, ¶ms);
+ }
return 0;
}
-int __connman_device_set_blocked(struct connman_device *device,
- connman_bool_t blocked)
+bool connman_device_get_powered(struct connman_device *device)
{
- connman_bool_t powered;
-
- DBG("device %p blocked %d", device, blocked);
-
- device->blocked = blocked;
-
- if (device->offlinemode == TRUE)
- return 0;
-
- connman_info("%s {rfkill} blocked %d", device->interface, blocked);
-
- if (blocked == FALSE)
- powered = device->powered_persistent;
- else
- powered = FALSE;
-
- return set_powered(device, powered);
+ return device->powered;
}
-connman_bool_t __connman_device_get_blocked(struct connman_device *device)
+static int device_scan(enum connman_service_type type,
+ struct connman_device *device,
+ bool force_full_scan)
{
- return device->blocked;
-}
+ struct connman_device_scan_params params;
-static int device_scan(struct connman_device *device)
-{
if (!device->driver || !device->driver->scan)
return -EOPNOTSUPP;
- if (device->powered == FALSE)
+ if (!device->powered)
return -ENOLINK;
- reset_scan_trigger(device);
-
- return device->driver->scan(device);
-}
-
-int __connman_device_enable_persistent(struct connman_device *device)
-{
- DBG("device %p", device);
-
- device->powered_persistent = TRUE;
-
- __connman_storage_save_device(device);
-
- return __connman_device_enable(device);
-}
-
-int __connman_device_disable_persistent(struct connman_device *device)
-{
- DBG("device %p", device);
-
- device->powered_persistent = FALSE;
-
- __connman_storage_save_device(device);
+ memset(¶ms, 0, sizeof(params));
+ params.type = type;
+ params.force_full_scan = force_full_scan;
- return __connman_device_disable(device);
+ return device->driver->scan(device, ¶ms);
}
int __connman_device_disconnect(struct connman_device *device)
DBG("device %p", device);
- connman_device_set_disconnected(device, TRUE);
-
g_hash_table_iter_init(&iter, device->networks);
- while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
struct connman_network *network = value;
- if (connman_network_get_connecting(network) == TRUE) {
+ if (connman_network_get_connecting(network)) {
/*
* Skip network in the process of connecting.
* This is a workaround for WiFi networks serviced
return 0;
}
-static void mark_network_available(gpointer key, gpointer value,
- gpointer user_data)
+int connman_device_reconnect_service(struct connman_device *device)
{
- struct connman_network *network = value;
+ DBG("device %p", device);
+
+ __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
- connman_network_set_available(network, TRUE);
+ return 0;
}
-static void mark_network_unavailable(gpointer key, gpointer value,
- gpointer user_data)
+#if defined TIZEN_EXT
+bool connman_device_set_last_user_selection_time(struct connman_device *device,
+ time_t time)
{
- struct connman_network *network = value;
+ if (device->last_user_selection_time != time) {
+ device->last_user_selection_time = time;
+ return true;
+ }
- if (connman_network_get_connected(network) == TRUE)
- return;
+ return false;
+}
- connman_network_set_available(network, FALSE);
+time_t connman_device_get_last_user_selection_time(struct connman_device *device)
+{
+ return device->last_user_selection_time;
}
-static gboolean remove_unavailable_network(gpointer key, gpointer value,
- gpointer user_data)
+bool connman_device_set_last_user_selection_ident(struct connman_device *device,
+ const char *ident)
{
- struct connman_network *network = value;
+ if (g_strcmp0(device->last_user_selection_ident, ident) != 0) {
+ g_free(device->last_user_selection_ident);
+ device->last_user_selection_ident = g_strdup(ident);
- if (connman_network_get_connected(network) == TRUE)
- return FALSE;
+ return true;
+ }
- if (connman_network_get_available(network) == TRUE)
- return FALSE;
+ return false;
+}
- return TRUE;
+const char *connman_device_get_last_user_selection_ident(struct connman_device *device)
+{
+ return device->last_user_selection_ident;
}
-void __connman_device_cleanup_networks(struct connman_device *device)
+bool connman_device_set_last_connected_ident(struct connman_device *device,
+ const char *ident)
{
- g_hash_table_foreach_remove(device->networks,
- remove_unavailable_network, NULL);
+ if (g_strcmp0(device->last_connected_ident, ident) != 0) {
+ g_free(device->last_connected_ident);
+ device->last_connected_ident = g_strdup(ident);
+
+ return true;
+ }
+
+ return false;
}
-connman_bool_t __connman_device_scanning(struct connman_device *device)
+const char *connman_device_get_last_connected_ident(struct connman_device *device)
{
- return device->scanning;
+ return device->last_connected_ident;
}
-void connman_device_reset_scanning(struct connman_device *device)
+void connman_device_save_last_user_selection(struct connman_device *device)
{
- device->scanning = FALSE;
+ GKeyFile *keyfile;
+ gchar *get_str;
+ gchar *selection_str;
- g_hash_table_foreach(device->networks,
- mark_network_available, NULL);
+ keyfile = __connman_storage_load_ins();
+
+ selection_str = g_strdup_printf("%s:%ld",
+ device->last_user_selection_ident, device->last_user_selection_time);
+
+ if (!keyfile) {
+ keyfile = g_key_file_new();
+
+ g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str);
+ DBG("%s", selection_str);
+ __connman_storage_save_ins(keyfile);
+
+ } else {
+ get_str = g_key_file_get_string(keyfile, device->interface, "LastUserSelection", NULL);
+ if (!get_str || g_strcmp0(get_str, selection_str) != 0) {
+ g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str);
+ DBG("%s -> %s", get_str, selection_str);
+ __connman_storage_save_ins(keyfile);
+ }
+
+ g_free(get_str);
+ }
+ g_free(selection_str);
+ g_key_file_free(keyfile);
}
-/**
- * connman_device_set_scanning:
- * @device: device structure
- * @scanning: scanning state
- *
- * Change scanning state of device
- */
-int connman_device_set_scanning(struct connman_device *device,
- connman_bool_t scanning)
+void connman_device_load_last_user_selection(struct connman_device *device)
{
- DBG("device %p scanning %d", device, scanning);
+ GKeyFile *keyfile;
+ gchar *get_str;
+ char **selection_str;
- if (!device->driver || !device->driver->scan)
- return -EINVAL;
+ keyfile = __connman_storage_load_ins();
+ if (!keyfile)
+ return;
- if (device->scanning == scanning)
- return -EALREADY;
+ get_str = g_key_file_get_string(keyfile, device->interface, "LastUserSelection", NULL);
+ if (get_str) {
+ selection_str = g_strsplit(get_str, ":", 0);
+ if (selection_str) {
+ time_t ref_time;
+ struct tm* timeinfo;
+ time_t last_user_selection_time;
- device->scanning = scanning;
+ /* Only events that occur within 8 hours are counted. */
+ ref_time = time(NULL);
+ timeinfo = localtime(&ref_time);
+ timeinfo->tm_hour -= 8;
+ ref_time = mktime(timeinfo);
- if (scanning == TRUE) {
- reset_scan_trigger(device);
+ last_user_selection_time = strtol(selection_str[1], NULL, 10);
- g_hash_table_foreach(device->networks,
- mark_network_unavailable, NULL);
+ if (last_user_selection_time > ref_time) {
+ if (g_strcmp0(selection_str[0], device->last_user_selection_ident) != 0) {
+ g_free(device->last_user_selection_ident);
+ device->last_user_selection_ident = g_strdup(selection_str[0]);
+ }
- return 0;
- }
+ device->last_user_selection_time = last_user_selection_time;
- __connman_device_cleanup_networks(device);
+ DBG("%s %ld", device->last_user_selection_ident, device->last_user_selection_time);
+ }
- if (device->connections > 0)
- return 0;
+ g_strfreev(selection_str);
+ }
- __connman_service_auto_connect();
+ g_free(get_str);
+ }
- return 0;
+ g_key_file_free(keyfile);
}
-/**
- * connman_device_set_disconnected:
- * @device: device structure
- * @disconnected: disconnected state
- *
- * Change disconnected state of device (only for device with networks)
- */
-int connman_device_set_disconnected(struct connman_device *device,
- connman_bool_t disconnected)
+void connman_device_save_last_connected(struct connman_device *device)
{
- DBG("device %p disconnected %d", device, disconnected);
+ GKeyFile *keyfile;
+ gchar *get_str;
- if (device->disconnected == disconnected)
- return -EALREADY;
+ if (!device->last_connected_ident)
+ return;
- device->disconnected = disconnected;
+ keyfile = __connman_storage_load_ins();
- if (disconnected == TRUE)
- force_scan_trigger(device);
+ if (!keyfile) {
+ keyfile = g_key_file_new();
- return 0;
+ g_key_file_set_string(keyfile, device->interface, "LastConnected", device->last_connected_ident);
+ DBG("%s", device->last_connected_ident);
+ __connman_storage_save_ins(keyfile);
+
+ } else {
+ get_str = g_key_file_get_string(keyfile, device->interface, "LastConnected", NULL);
+ if (!get_str || g_strcmp0(get_str, device->last_connected_ident) != 0) {
+ g_key_file_set_string(keyfile, device->interface, "LastConnected", device->last_connected_ident);
+ DBG("%s -> %s", get_str, device->last_connected_ident);
+ __connman_storage_save_ins(keyfile);
+ }
+
+ g_free(get_str);
+ }
+
+ g_key_file_free(keyfile);
}
-/**
- * connman_device_get_disconnected:
- * @device: device structure
+void connman_device_load_last_connected(struct connman_device *device)
+{
+ GKeyFile *keyfile;
+ gchar *get_str;
+
+ keyfile = __connman_storage_load_ins();
+ if (!keyfile)
+ return;
+
+ get_str = g_key_file_get_string(keyfile, device->interface, "LastConnected", NULL);
+ if (get_str) {
+ if (g_strcmp0(get_str, device->last_connected_ident) != 0) {
+ g_free(device->last_connected_ident);
+ device->last_connected_ident = g_strdup(get_str);
+ }
+
+ DBG("%s", device->last_connected_ident);
+
+ g_free(get_str);
+ }
+
+ g_key_file_free(keyfile);
+}
+#endif
+
+static void mark_network_available(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_network *network = value;
+
+ connman_network_set_available(network, true);
+}
+
+static void mark_network_unavailable(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_network *network = value;
+
+ if (connman_network_get_connected(network) ||
+ connman_network_get_connecting(network))
+ return;
+
+ connman_network_set_available(network, false);
+}
+
+static gboolean remove_unavailable_network(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct connman_network *network = value;
+
+ if (connman_network_get_connected(network) ||
+ connman_network_get_connecting(network))
+ return FALSE;
+
+ if (connman_network_get_available(network))
+ return FALSE;
+
+ return TRUE;
+}
+
+void __connman_device_cleanup_networks(struct connman_device *device)
+{
+ g_hash_table_foreach_remove(device->networks,
+ remove_unavailable_network, NULL);
+}
+
+bool connman_device_get_scanning(struct connman_device *device,
+ enum connman_service_type type)
+{
+ int i;
+
+ if (type != CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return device->scanning[type];
+
+ for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
+ if (device->scanning[i])
+ return true;
+
+ return false;
+}
+
+void connman_device_reset_scanning(struct connman_device *device)
+{
+ g_hash_table_foreach(device->networks,
+ mark_network_available, NULL);
+}
+
+/**
+ * connman_device_set_scanning:
+ * @device: device structure
+ * @scanning: scanning state
*
- * Get device disconnected state
+ * Change scanning state of device
*/
-connman_bool_t connman_device_get_disconnected(struct connman_device *device)
+int connman_device_set_scanning(struct connman_device *device,
+ enum connman_service_type type, bool scanning)
{
- return device->disconnected;
+ DBG("device %p scanning %d", device, scanning);
+
+ if (!device->driver || !device->driver->scan)
+ return -EINVAL;
+
+ if (type == CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return -EINVAL;
+
+ if (device->scanning[type] == scanning)
+ return -EALREADY;
+
+ device->scanning[type] = scanning;
+
+ if (scanning) {
+ __connman_technology_scan_started(device);
+
+ g_hash_table_foreach(device->networks,
+ mark_network_unavailable, NULL);
+
+ return 0;
+ }
+
+ __connman_device_cleanup_networks(device);
+
+ __connman_technology_scan_stopped(device, type);
+
+ __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+
+#if defined TIZEN_EXT_WIFI_MESH
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ __connman_mesh_auto_connect();
+#endif
+
+ return 0;
}
/**
{
DBG("device %p key %s value %s", device, key, value);
- if (g_str_equal(key, "Address") == TRUE) {
+ if (g_str_equal(key, "Address")) {
g_free(device->address);
device->address = g_strdup(value);
- } else if (g_str_equal(key, "Name") == TRUE) {
+ } else if (g_str_equal(key, "Name")) {
g_free(device->name);
device->name = g_strdup(value);
- } else if (g_str_equal(key, "Node") == TRUE) {
+ } else if (g_str_equal(key, "Node")) {
g_free(device->node);
device->node = g_strdup(value);
- } else if (g_str_equal(key, "Path") == TRUE) {
+ } else if (g_str_equal(key, "Path")) {
g_free(device->path);
device->path = g_strdup(value);
} else {
{
DBG("device %p key %s", device, key);
- if (g_str_equal(key, "Address") == TRUE)
+ if (g_str_equal(key, "Address"))
return device->address;
- else if (g_str_equal(key, "Name") == TRUE)
+ else if (g_str_equal(key, "Name"))
return device->name;
- else if (g_str_equal(key, "Node") == TRUE)
+ else if (g_str_equal(key, "Node"))
return device->node;
- else if (g_str_equal(key, "Interface") == TRUE)
+ else if (g_str_equal(key, "Interface"))
return device->interface;
- else if (g_str_equal(key, "Path") == TRUE)
+ else if (g_str_equal(key, "Path"))
return device->path;
return NULL;
}
-void __connman_device_increase_connections(struct connman_device *device)
-{
- if (device == NULL)
- return;
-
- device->connections++;
-}
-
-void __connman_device_decrease_connections(struct connman_device *device)
-{
- if (device == NULL)
- return;
-
- device->connections--;
-
- if (device->connections == 0)
- device->backoff_interval = SCAN_INITIAL_DELAY;
-}
-
/**
* connman_device_add_network:
* @device: device structure
DBG("device %p network %p", device, network);
- if (identifier == NULL)
+ if (!identifier)
return -EINVAL;
connman_network_ref(network);
__connman_network_set_device(network, device);
- g_hash_table_insert(device->networks, g_strdup(identifier),
+ g_hash_table_replace(device->networks, g_strdup(identifier),
network);
return 0;
return g_hash_table_lookup(device->networks, identifier);
}
+#if defined TIZEN_EXT
+struct connman_network *connman_device_get_default_network(
+ struct connman_device *device)
+{
+ return device->network;
+}
+
+void connman_device_set_pending_reply(struct connman_device *device,
+ DBusMessage *msg)
+{
+ device->pending_reply = dbus_message_ref(msg);
+}
+
+void connman_device_send_connected_signal(struct connman_device *device,
+ bool connected)
+{
+ enum connman_service_type type;
+
+ if (!device)
+ return;
+
+ type = __connman_device_get_service_type(device);
+ device_send_changed(device->interface, type, "Connected", connected);
+}
+
+void connman_device_set_max_scan_ssids(struct connman_device *device,
+ int max_scan_ssids)
+{
+ device->max_scan_ssids = max_scan_ssids;
+}
+
+int connman_device_get_max_scan_ssids(struct connman_device *device)
+{
+ return device->max_scan_ssids;
+}
+
+void connman_device_set_wifi_5ghz_supported(struct connman_device *device,
+ bool is_5_0_ghz_supported)
+{
+ device->is_5_0_ghz_supported = is_5_0_ghz_supported;
+}
+
+bool connman_device_get_wifi_5ghz_supported(struct connman_device *device)
+{
+ return device->is_5_0_ghz_supported;
+}
+#endif
+
/**
* connman_device_remove_network:
* @device: device structure
DBG("device %p network %p", device, network);
- if (network == NULL)
+ if (!network)
return 0;
identifier = connman_network_get_identifier(network);
return 0;
}
-void connman_device_remove_all_networks(struct connman_device *device)
-{
- g_hash_table_remove_all(device->networks);
-}
-
void __connman_device_set_network(struct connman_device *device,
struct connman_network *network)
{
const char *name;
- if (device == NULL)
+ if (!device)
return;
if (device->network == network)
return;
- if (network != NULL) {
+ if (network) {
name = connman_network_get_string(network, "Name");
g_free(device->last_network);
device->last_network = g_strdup(name);
}
}
-void __connman_device_set_reconnect(struct connman_device *device,
- connman_bool_t reconnect)
-{
- device->reconnect = reconnect;
-}
-
-connman_bool_t __connman_device_get_reconnect(
- struct connman_device *device)
-{
- return device->reconnect;
-}
-
-static gboolean match_driver(struct connman_device *device,
+static bool match_driver(struct connman_device *device,
struct connman_device_driver *driver)
{
if (device->type == driver->type ||
driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
-static int device_probe(struct connman_device *device)
+/**
+ * connman_device_register:
+ * @device: device structure
+ *
+ * Register device with the system
+ */
+int connman_device_register(struct connman_device *device)
{
GSList *list;
DBG("device %p name %s", device, device->name);
- if (device->driver != NULL)
+ if (device->driver)
return -EALREADY;
for (list = driver_list; list; list = list->next) {
struct connman_device_driver *driver = list->data;
- if (match_driver(device, driver) == FALSE)
+ if (!match_driver(device, driver))
continue;
DBG("driver %p name %s", driver, driver->name);
}
}
- if (device->driver == NULL)
+ if (!device->driver)
return 0;
- return setup_device(device);
-}
-
-static void device_remove(struct connman_device *device)
-{
- DBG("device %p name %s", device, device->name);
-
- if (device->driver == NULL)
- return;
-
- remove_device(device);
-}
-
-/**
- * connman_device_register:
- * @device: device structure
- *
- * Register device with the system
- */
-int connman_device_register(struct connman_device *device)
-{
- __connman_storage_load_device(device);
-
- device->offlinemode = __connman_profile_get_offlinemode();
-
- return device_probe(device);
+ return __connman_technology_add_device(device);
}
/**
*/
void connman_device_unregister(struct connman_device *device)
{
- __connman_storage_save_device(device);
+ DBG("device %p name %s", device, device->name);
+
+ if (!device->driver)
+ return;
- device_remove(device);
+ remove_device(device);
}
/**
{
GSList *list;
- for (list = device_list; list != NULL; list = list->next) {
+ for (list = device_list; list; list = list->next) {
struct connman_device *device = list->data;
enum connman_service_type service_type =
__connman_device_get_service_type(device);
return NULL;
}
-int __connman_device_request_scan(enum connman_service_type type)
+struct connman_device *connman_device_find_by_index(int index)
+{
+ GSList *list;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+ if (device->index == index)
+ return device;
+ }
+
+ return NULL;
+}
+
+/**
+ * connman_device_set_regdom
+ * @device: device structure
+ * @alpha2: string representing regulatory domain
+ *
+ * Set regulatory domain on device basis
+ */
+int connman_device_set_regdom(struct connman_device *device,
+ const char *alpha2)
+{
+ if (!device->driver || !device->driver->set_regdom)
+ return -ENOTSUP;
+
+ if (!device->powered)
+ return -EINVAL;
+
+ return device->driver->set_regdom(device, alpha2);
+}
+
+/**
+ * connman_device_regdom_notify
+ * @device: device structure
+ * @alpha2: string representing regulatory domain
+ *
+ * Notify on setting regulatory domain on device basis
+ */
+void connman_device_regdom_notify(struct connman_device *device,
+ int result, const char *alpha2)
+{
+ __connman_technology_notify_regdom_by_device(device, result, alpha2);
+}
+
+#if defined TIZEN_EXT
+static int device_specific_scan(enum connman_service_type type,
+ struct connman_device *device,
+ int scan_type, GSList *specific_scan_list)
+{
+ if (!device->driver || !device->driver->specific_scan)
+ return -EOPNOTSUPP;
+
+ if (!device->powered)
+ return -ENOLINK;
+
+ return device->driver->specific_scan(type, device, scan_type,
+ specific_scan_list, NULL);
+}
+
+int __connman_device_request_specific_scan(enum connman_service_type type,
+ const char *ifname, int scan_type, GSList *specific_scan_list)
{
+ bool success = false;
+ int last_err = -ENOSYS;
GSList *list;
int err;
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_GADGET:
- return 0;
+ return -EOPNOTSUPP;
case CONNMAN_SERVICE_TYPE_WIFI:
- case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
break;
}
- for (list = device_list; list != NULL; list = list->next) {
+ for (list = device_list; list; list = list->next) {
struct connman_device *device = list->data;
enum connman_service_type service_type =
__connman_device_get_service_type(device);
- if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
- service_type != type) {
+ if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
+ if (type == CONNMAN_SERVICE_TYPE_P2P) {
+ if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+ } else if (service_type != type)
+ continue;
+ }
+
+ if (ifname && g_strcmp0(device->interface, ifname) != 0)
continue;
+
+ err = device_specific_scan(type, device, scan_type, specific_scan_list);
+ if (err == 0 || err == -EINPROGRESS) {
+ success = true;
+ } else {
+ last_err = err;
+ DBG("device %p err %d", device, err);
}
+ }
- err = device_scan(device);
- if (err < 0 && err != -EINPROGRESS) {
- DBG("err %d", err);
- /* XXX maybe only a continue? */
- return err;
+ if (success)
+ return 0;
+
+ return last_err;
+}
+
+int connman_device_request_device_scan(enum connman_service_type type,
+ const char * ifname, bool force_full_scan)
+{
+ bool success = false;
+ int last_err = -ENOSYS;
+ GSList *list;
+ int err;
+
+ switch (type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ return -EOPNOTSUPP;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
+ break;
+ }
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ if (!device_has_service_type(device, type))
+ continue;
+
+ if (g_strcmp0(device->interface, ifname) != 0)
+ continue;
+
+ err = device_scan(type, device, force_full_scan);
+
+ if (err == 0 || err == -EINPROGRESS) {
+ success = true;
+ } else {
+ last_err = err;
+ DBG("device %p err %d", device, err);
}
+ break;
}
- return 0;
+ if (success)
+ return 0;
+
+ return last_err;
}
-connman_bool_t __connman_device_isfiltered(const char *devname)
+#if defined TIZEN_EXT_WIFI_MESH
+static int device_abort_scan(enum connman_service_type type,
+ struct connman_device *device)
{
- char **pattern;
+ if (!device->driver || !device->driver->scan)
+ return -EOPNOTSUPP;
- if (device_filter == NULL)
- goto nodevice;
+ if (!device->powered)
+ return -ENOLINK;
+
+ return device->driver->abort_scan(type, device);
+}
+
+int __connman_device_abort_scan(enum connman_service_type type)
+{
+ GSList *list;
+ int err = -EINVAL;
- for (pattern = device_filter; *pattern; pattern++) {
- if (g_pattern_match_simple(*pattern, devname) == FALSE) {
- DBG("ignoring device %s (match)", devname);
- return TRUE;
+ if (type != CONNMAN_SERVICE_TYPE_MESH)
+ return -EINVAL;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+ enum connman_service_type service_type =
+ __connman_device_get_service_type(device);
+
+ if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+
+ if (!device->scanning) {
+ err = -EEXIST;
+ continue;
+ }
+
+ err = device_abort_scan(type, device);
}
}
+ return err;
+}
-nodevice:
- if (g_pattern_match_simple("dummy*", devname) == TRUE) {
- DBG("ignoring dummy networking devices");
- return TRUE;
+static int device_mesh_specific_scan(enum connman_service_type type,
+ struct connman_device *device, const char *name,
+ unsigned int freq)
+{
+ if (!device->driver || !device->driver->mesh_specific_scan)
+ return -EOPNOTSUPP;
+
+ if (!device->powered)
+ return -ENOLINK;
+
+ return device->driver->mesh_specific_scan(type, device, name, freq, NULL);
+}
+
+int __connman_device_request_mesh_specific_scan(enum connman_service_type type,
+ const char *name,
+ unsigned int freq)
+{
+ bool success = false;
+ int last_err = -ENOSYS;
+ GSList *list;
+ int err;
+
+ if (type != CONNMAN_SERVICE_TYPE_MESH)
+ return -EINVAL;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+ enum connman_service_type service_type =
+ __connman_device_get_service_type(device);
+
+ if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
+ if (type == CONNMAN_SERVICE_TYPE_MESH)
+ if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
+ continue;
+ }
+
+ err = device_mesh_specific_scan(type, device, name, freq);
+ if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
+ success = true;
+ } else {
+ last_err = err;
+ DBG("device %p err %d", device, err);
+ }
}
- if (nodevice_filter == NULL)
- return FALSE;
+ if (success)
+ return 0;
- for (pattern = nodevice_filter; *pattern; pattern++) {
- if (g_pattern_match_simple(*pattern, devname) == TRUE) {
- DBG("ignoring device %s (no match)", devname);
- return TRUE;
+ return last_err;
+}
+#endif /* TIZEN_EXT_WIFI_MESH */
+#endif
+
+static int connman_device_request_scan(enum connman_service_type type,
+ bool force_full_scan)
+{
+ bool success = false;
+ int last_err = -ENOSYS;
+ GSList *list;
+ int err;
+
+ switch (type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ return -EOPNOTSUPP;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+ case CONNMAN_SERVICE_TYPE_MESH:
+#endif
+ break;
+ }
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ if (!device_has_service_type(device, type))
+ continue;
+
+ err = device_scan(type, device, force_full_scan);
+#if defined TIZEN_EXT
+ /* When Scan is already in progress then return Error so that
+ * wifi-manager can block the scan-done signal to be sent to
+ * application and start requested scan after scan already in progress
+ * is completed then notify to application about the scan event */
+ if (err == 0 || err == -EINPROGRESS) {
+#else
+ if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
+#endif
+ success = true;
+ } else {
+ last_err = err;
+ DBG("device %p err %d", device, err);
}
}
- return FALSE;
+ if (success)
+ return 0;
+
+ return last_err;
}
-static int device_load(struct connman_device *device)
+int __connman_device_request_scan(enum connman_service_type type)
{
- const char *ident = __connman_profile_active_ident();
- GKeyFile *keyfile;
- GError *error = NULL;
- gchar *identifier;
- connman_bool_t powered;
+ return connman_device_request_scan(type, false);
+}
+
+int __connman_device_request_scan_full(enum connman_service_type type)
+{
+ return connman_device_request_scan(type, true);
+}
+
+int __connman_device_request_hidden_scan(struct connman_device *device,
+ const char *ssid, unsigned int ssid_len,
+ const char *identity, const char *passphrase,
+ const char *security, void *user_data)
+{
+ struct connman_device_scan_params params;
DBG("device %p", device);
- keyfile = __connman_storage_open_profile(ident);
- if (keyfile == NULL)
- return 0;
+ if (!device || !device->driver ||
+ !device->driver->scan)
+ return -EINVAL;
- identifier = g_strdup_printf("device_%s", device->name);
- if (identifier == NULL)
- goto done;
+ params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
+ params.ssid = ssid;
+ params.ssid_len = ssid_len;
+ params.identity = identity;
+ params.passphrase = passphrase;
+ params.security = security;
+ params.user_data = user_data;
- powered = g_key_file_get_boolean(keyfile, identifier,
- "Powered", &error);
- if (error == NULL)
- device->powered_persistent = powered;
- g_clear_error(&error);
+ return device->driver->scan(device, ¶ms);
+}
-done:
- g_free(identifier);
+void __connman_device_stop_scan(enum connman_service_type type)
+{
+ GSList *list;
- __connman_storage_close_profile(ident, keyfile, FALSE);
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
- return 0;
+ if (!device_has_service_type(device, type))
+ continue;
+
+ if (device->driver && device->driver->stop_scan)
+ device->driver->stop_scan(type, device);
+ }
}
-static int device_save(struct connman_device *device)
+#if defined TIZEN_EXT
+char *index2ident(int index, const char *prefix)
+#else
+static char *index2ident(int index, const char *prefix)
+#endif
{
- const char *ident = __connman_profile_active_ident();
- GKeyFile *keyfile;
- gchar *identifier;
+ struct ifreq ifr;
+ struct ether_addr eth;
+ char *str;
+ int sk, err, len;
- DBG("device %p", device);
+ if (index < 0)
+ return NULL;
- keyfile = __connman_storage_open_profile(ident);
- if (keyfile == NULL)
- return 0;
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return NULL;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ if (err == 0)
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return NULL;
- identifier = g_strdup_printf("device_%s", device->name);
- if (identifier == NULL)
+ len = prefix ? strlen(prefix) + 18 : 18;
+
+ str = g_malloc(len);
+ if (!str)
+ return NULL;
+
+ memcpy(ð, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
+ snprintf(str, len, "%s%02x%02x%02x%02x%02x%02x",
+ prefix ? prefix : "",
+ eth.ether_addr_octet[0],
+ eth.ether_addr_octet[1],
+ eth.ether_addr_octet[2],
+ eth.ether_addr_octet[3],
+ eth.ether_addr_octet[4],
+ eth.ether_addr_octet[5]);
+
+ return str;
+}
+
+#if defined TIZEN_EXT
+char *index2addr(int index)
+#else
+static char *index2addr(int index)
+#endif
+{
+ struct ifreq ifr;
+ struct ether_addr eth;
+ char *str;
+ int sk, err;
+
+ if (index < 0)
+ return NULL;
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return NULL;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+
+ if (err == 0)
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+
+ close(sk);
+
+ if (err < 0)
+ return NULL;
+
+ str = g_malloc(18);
+ if (!str)
+ return NULL;
+
+ memcpy(ð, &ifr.ifr_hwaddr.sa_data, sizeof(eth));
+ snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
+ eth.ether_addr_octet[0],
+ eth.ether_addr_octet[1],
+ eth.ether_addr_octet[2],
+ eth.ether_addr_octet[3],
+ eth.ether_addr_octet[4],
+ eth.ether_addr_octet[5]);
+
+ return str;
+}
+
+struct connman_device *connman_device_create_from_index(int index)
+{
+ enum connman_device_type type;
+ struct connman_device *device;
+ char *devname, *ident = NULL;
+ char *addr = NULL, *name = NULL;
+
+ if (index < 0)
+ return NULL;
+
+ devname = connman_inet_ifname(index);
+ if (!devname)
+ return NULL;
+
+ if (__connman_device_isfiltered(devname)) {
+ connman_info("Ignoring interface %s (filtered)", devname);
+ g_free(devname);
+ return NULL;
+ }
+
+ type = __connman_rtnl_get_device_type(index);
+
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ connman_info("Ignoring interface %s (type unknown)", devname);
+ g_free(devname);
+ return NULL;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_GADGET:
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ name = index2ident(index, "");
+ addr = index2addr(index);
+ break;
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ case CONNMAN_DEVICE_TYPE_CELLULAR:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ name = g_strdup(devname);
+ break;
+ }
+
+ device = connman_device_create(name, type);
+ if (!device)
goto done;
- g_key_file_set_boolean(keyfile, identifier,
- "Powered", device->powered_persistent);
+ switch (type) {
+ case CONNMAN_DEVICE_TYPE_UNKNOWN:
+ case CONNMAN_DEVICE_TYPE_VENDOR:
+ case CONNMAN_DEVICE_TYPE_GPS:
+ break;
+ case CONNMAN_DEVICE_TYPE_ETHERNET:
+ case CONNMAN_DEVICE_TYPE_GADGET:
+ ident = index2ident(index, NULL);
+ break;
+ case CONNMAN_DEVICE_TYPE_WIFI:
+ ident = index2ident(index, NULL);
+ break;
+ case CONNMAN_DEVICE_TYPE_BLUETOOTH:
+ break;
+ case CONNMAN_DEVICE_TYPE_CELLULAR:
+ ident = index2ident(index, NULL);
+ break;
+ }
+
+ connman_device_set_index(device, index);
+ connman_device_set_interface(device, devname);
+#if defined TIZEN_EXT
+ connman_device_load_last_connected(device);
+ connman_device_load_last_user_selection(device);
+#endif
+
+ if (ident) {
+ connman_device_set_ident(device, ident);
+ g_free(ident);
+ }
+
+ connman_device_set_string(device, "Address", addr);
done:
- g_free(identifier);
+ g_free(devname);
+ g_free(name);
+ g_free(addr);
- __connman_storage_close_profile(ident, keyfile, TRUE);
+ return device;
+}
- return 0;
+bool __connman_device_isfiltered(const char *devname)
+{
+ char **pattern;
+ char **blacklisted_interfaces;
+ bool match;
+
+ if (!device_filter)
+ goto nodevice;
+
+ for (pattern = device_filter, match = false; *pattern; pattern++) {
+ if (g_pattern_match_simple(*pattern, devname)) {
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ DBG("ignoring device %s (match)", devname);
+ return true;
+ }
+
+nodevice:
+ if (g_pattern_match_simple("dummy*", devname)) {
+ DBG("ignoring dummy networking devices");
+ return true;
+ }
+
+ if (!nodevice_filter)
+ goto list;
+
+ for (pattern = nodevice_filter; *pattern; pattern++) {
+ if (g_pattern_match_simple(*pattern, devname)) {
+ DBG("ignoring device %s (no match)", devname);
+ return true;
+ }
+ }
+
+list:
+ if (__connman_inet_isrootnfs_device(devname)) {
+ DBG("ignoring device %s (rootnfs)", devname);
+ return true;
+ }
+
+ blacklisted_interfaces =
+ connman_setting_get_string_list("NetworkInterfaceBlacklist");
+ if (!blacklisted_interfaces)
+ return false;
+
+ for (pattern = blacklisted_interfaces; *pattern; pattern++) {
+ if (g_str_has_prefix(devname, *pattern)) {
+ DBG("ignoring device %s (blacklist)", devname);
+ return true;
+ }
+ }
+
+ return false;
}
-static struct connman_storage device_storage = {
- .name = "device",
- .priority = CONNMAN_STORAGE_PRIORITY_LOW,
- .device_load = device_load,
- .device_save = device_save,
-};
+static void cleanup_devices(void)
+{
+ /*
+ * Check what interfaces are currently up and if connman is
+ * suppose to handle the interface, then cleanup the mess
+ * related to that interface. There might be weird routes etc
+ * that are related to that interface and that might confuse
+ * connmand. So in this case we just turn the interface down
+ * so that kernel removes routes/addresses automatically and
+ * then proceed the startup.
+ *
+ * Note that this cleanup must be done before rtnl/detect code
+ * has activated interface watches.
+ */
+
+ char **interfaces;
+ int i;
+
+ interfaces = __connman_inet_get_running_interfaces();
+
+ if (!interfaces)
+ return;
+
+ for (i = 0; interfaces[i]; i++) {
+ bool filtered;
+ int index;
+ struct sockaddr_in sin_addr, sin_mask;
+
+ filtered = __connman_device_isfiltered(interfaces[i]);
+ if (filtered)
+ continue;
+
+ index = connman_inet_ifindex(interfaces[i]);
+ if (index < 0)
+ continue;
+
+ if (!__connman_inet_get_address_netmask(index, &sin_addr,
+ &sin_mask)) {
+ char *address = g_strdup(inet_ntoa(sin_addr.sin_addr));
+ char *netmask = g_strdup(inet_ntoa(sin_mask.sin_addr));
+
+ if (__connman_config_address_provisioned(address,
+ netmask)) {
+ DBG("Skip %s which is already provisioned "
+ "with %s/%s", interfaces[i], address,
+ netmask);
+ g_free(address);
+ g_free(netmask);
+ continue;
+ }
+
+ g_free(address);
+ g_free(netmask);
+ }
+
+ DBG("cleaning up %s index %d", interfaces[i], index);
+
+#if defined TIZEN_EXT
+ if (strcmp(interfaces[i], "wlan0") != 0)
+#endif
+ connman_inet_ifdown(index);
+
+ /*
+ * ConnMan will turn the interface UP automatically so
+ * no need to do it here.
+ */
+ }
+
+ g_strfreev(interfaces);
+}
int __connman_device_init(const char *device, const char *nodevice)
{
DBG("");
- if (device != NULL)
+#if defined TIZEN_EXT
+ connection = connman_dbus_get_connection();
+#endif
+
+ if (device)
device_filter = g_strsplit(device, ",", -1);
- if (nodevice != NULL)
+ if (nodevice)
nodevice_filter = g_strsplit(nodevice, ",", -1);
- return connman_storage_register(&device_storage);
+ cleanup_devices();
+
+ return 0;
}
void __connman_device_cleanup(void)
g_strfreev(nodevice_filter);
g_strfreev(device_filter);
- connman_storage_unregister(&device_storage);
+#if defined TIZEN_EXT
+ dbus_connection_unref(connection);
+#endif
}