X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdevice.c;h=535028217e5e3d712e4434bdfdf160c31681133d;hb=688ac80683ad821a126c2f612815475bc6896fb5;hp=12fa49a0723cae120690eac97f9a99a4260675c0;hpb=fcfc5cc4268e7458a64b22d31537473327fed6a8;p=platform%2Fupstream%2Fconnman.git diff --git a/src/device.c b/src/device.c old mode 100644 new mode 100755 index 12fa49a..5350282 --- a/src/device.c +++ b/src/device.c @@ -2,7 +2,7 @@ * * 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 @@ -25,6 +25,12 @@ #include #include +#include +#include +#include +#include +#include +#include #include "connman.h" @@ -32,30 +38,33 @@ static GSList *device_list = NULL; 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, + PENDING_DISABLE = 2, +}; + struct connman_device { - gint refcount; + int refcount; enum connman_device_type type; - connman_bool_t offlinemode; - connman_bool_t blocked; - connman_bool_t powered; - connman_bool_t powered_pending; - 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; + enum connman_pending_type powered_pending; /* Indicates a pending + * 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; void *driver_data; @@ -63,73 +72,45 @@ struct connman_device { 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; + GList *pending_reply_list; /* List of DBusMessage* for async reply to multiple + * device power dbus calls, which are made before + * connman_device_set_powered(). + */ + int max_scan_ssids; + bool is_5_0_ghz_supported; + unsigned int mac_policy; + unsigned int preassoc_mac_policy; + unsigned int random_mac_lifetime; +#endif }; -#define SCAN_INITIAL_DELAY 10 - -static gboolean device_scan_trigger(gpointer user_data) +#if defined TIZEN_EXT +static void __clear_pending_trigger(gpointer data, 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; + DBusMessage *msg = (DBusMessage *)data; + dbus_message_unref(msg); } +#endif -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_list) { + g_list_foreach(device->pending_reply_list, __clear_pending_trigger, NULL); + g_list_free(device->pending_reply_list); + device->pending_reply_list = 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) { @@ -140,8 +121,6 @@ static const char *type2description(enum connman_device_type 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: @@ -166,8 +145,6 @@ static const char *type2string(enum connman_device_type type) 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: @@ -182,7 +159,8 @@ static const char *type2string(enum connman_device_type type) 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); @@ -195,8 +173,6 @@ enum connman_service_type __connman_device_get_service_type(struct connman_devic 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: @@ -209,109 +185,173 @@ enum connman_service_type __connman_device_get_service_type(struct connman_devic return CONNMAN_SERVICE_TYPE_UNKNOWN; } -int __connman_device_enable(struct connman_device *device) +static bool device_has_service_type(struct connman_device *device, + enum connman_service_type service_type) { - int err; - enum connman_service_type type; + enum connman_service_type device_service_type = + __connman_device_get_service_type(device); - DBG("device %p %d", device, device->blocked); + /* + * 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 (!device->driver || !device->driver->enable) - return -EOPNOTSUPP; +#if defined TIZEN_EXT_WIFI_MESH + if (device_service_type == CONNMAN_SERVICE_TYPE_MESH) + return service_type != CONNMAN_SERVICE_TYPE_MESH; +#endif - if (device->powered_pending == TRUE) - return -EALREADY; + if (device_service_type == CONNMAN_SERVICE_TYPE_WIFI) { + return service_type == CONNMAN_SERVICE_TYPE_WIFI || + service_type == CONNMAN_SERVICE_TYPE_P2P; + } - if (device->blocked == TRUE) - return -ENOLINK; + return service_type == device_service_type; +} + +#if defined TIZEN_EXT +static void __device_pending_reset(gpointer data, gpointer user_data) +{ + DBusMessage *msg = (DBusMessage *)data; + DBusMessage *reply; - connman_device_set_disconnected(device, FALSE); - device->scanning = FALSE; + reply = __connman_error_failed(msg, ETIMEDOUT); + if (reply) + g_dbus_send_message(connection, reply); - err = device->driver->enable(device); - if (err < 0 && err != -EALREADY) { - if (err == -EINPROGRESS) { - device->powered_pending = TRUE; - device->offlinemode = FALSE; - if (__connman_profile_get_offlinemode() == TRUE) - __connman_profile_set_offlinemode(FALSE, FALSE); - } - return err; - } + dbus_message_unref(msg); +} +#endif + +static gboolean device_pending_reset(gpointer user_data) +{ + struct connman_device *device = user_data; - device->powered_pending = TRUE; - device->powered = TRUE; - device->offlinemode = FALSE; - if (__connman_profile_get_offlinemode() == TRUE) - __connman_profile_set_offlinemode(FALSE, FALSE); + DBG("device %p", device); - type = __connman_device_get_service_type(device); - __connman_technology_enable(type); +#if defined TIZEN_EXT + DBusMessage *reply; - return 0; + /* Power request timed out, send ETIMEDOUT. */ + if (device->pending_reply_list) { + g_list_foreach(device->pending_reply_list, __device_pending_reset, NULL); + g_list_free(device->pending_reply_list); + device->pending_reply_list = NULL; + } +#endif + /* Power request timedout, reset power pending state. */ + device->pending_timeout = 0; + device->powered_pending = PENDING_NONE; + + return FALSE; } -int __connman_device_disable(struct connman_device *device) +int __connman_device_enable(struct connman_device *device) { int err; - enum connman_service_type type; DBG("device %p", device); - if (!device->driver || !device->driver->disable) + if (!device->driver || !device->driver->enable) return -EOPNOTSUPP; - if (device->powered == FALSE) - return -ENOLINK; + /* There is an ongoing power disable request. */ + if (device->powered_pending == PENDING_DISABLE) + return -EBUSY; - if (device->powered_pending == FALSE) + if (device->powered_pending == PENDING_ENABLE) + return -EINPROGRESS; + + if (device->powered_pending == PENDING_NONE && device->powered) return -EALREADY; - device->reconnect = FALSE; + if (device->index > 0) { + err = connman_inet_ifup(device->index); + if (err < 0 && err != -EALREADY) + return err; + } - clear_scan_trigger(device); + device->powered_pending = PENDING_ENABLE; - err = device->driver->disable(device); - if (err < 0 && err != -EALREADY) { - if (err == -EINPROGRESS) - device->powered_pending = FALSE; - return err; + err = device->driver->enable(device); + /* + * device gets enabled right away. + * Invoke the callback + */ + if (err == 0) { + connman_device_set_powered(device, true); + goto done; } - g_hash_table_remove_all(device->networks); + if (err == -EALREADY) { + /* If device is already powered, but connman is not updated */ + connman_device_set_powered(device, true); +#ifdef TIZEN_EXT + if (device->type == CONNMAN_DEVICE_TYPE_WIFI) { + device->driver->set_mac_policy(device, device->mac_policy); + device->driver->set_preassoc_mac_policy(device, device->preassoc_mac_policy); + device->driver->set_random_mac_lifetime(device, device->random_mac_lifetime); + } +#endif /* TIZEN_EXT */ + goto done; + } + /* + * if err == -EINPROGRESS, then the DBus call to the respective daemon + * was successful. We set a 10 sec timeout so if the daemon never + * returns a reply, we would reset the pending request. + */ + if (err == -EINPROGRESS) + device->pending_timeout = g_timeout_add_seconds(10, + device_pending_reset, device); +done: + return err; +} + +int __connman_device_disable(struct connman_device *device) +{ + int err; - device->connections = 0; + DBG("device %p", device); - device->powered_pending = FALSE; - device->powered = FALSE; + /* Ongoing power enable request */ + if (device->powered_pending == PENDING_ENABLE) + return -EBUSY; - type = __connman_device_get_service_type(device); - __connman_technology_disable(type); + if (device->powered_pending == PENDING_DISABLE) + return -EINPROGRESS; - return 0; -} + if (device->powered_pending == PENDING_NONE && !device->powered) + return -EALREADY; -static int set_powered(struct connman_device *device, connman_bool_t powered) -{ - DBG("device %p powered %d", device, powered); + device->powered_pending = PENDING_DISABLE; - if (powered == TRUE) - return __connman_device_enable(device); - else - return __connman_device_disable(device); -} + if (device->network) { + struct connman_service *service = + connman_service_lookup_from_network(device->network); -static int setup_device(struct connman_device *device) -{ - DBG("device %p", device); + if (service) + __connman_service_disconnect(service); + else + connman_network_set_connected(device->network, false); + } - __connman_technology_add_device(device); + if (!device->driver || !device->driver->disable) + return -EOPNOTSUPP; - if (device->offlinemode == FALSE && - device->powered_persistent == TRUE) - __connman_device_enable(device); + err = device->driver->disable(device); + if (err == 0 || err == -EALREADY) { + connman_device_set_powered(device, false); + goto done; + } - return 0; + if (err == -EINPROGRESS) + device->pending_timeout = g_timeout_add_seconds(4, + device_pending_reset, device); +done: + return err; } static void probe_driver(struct connman_device_driver *driver) @@ -320,10 +360,10 @@ static void probe_driver(struct connman_device_driver *driver) 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) @@ -334,7 +374,7 @@ static void probe_driver(struct connman_device_driver *driver) device->driver = driver; - setup_device(device); + __connman_technology_add_device(device); } } @@ -358,7 +398,7 @@ static void remove_driver(struct connman_device_driver *driver) 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) @@ -366,12 +406,12 @@ static void remove_driver(struct connman_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; @@ -433,7 +473,10 @@ static void device_destruct(struct connman_device *device) { 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); @@ -441,16 +484,68 @@ static void device_destruct(struct connman_device *device) 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(gpointer data, gpointer user_data) +{ + DBusMessage *msg = (DBusMessage *)data; + g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID); + dbus_message_unref(msg); +} + +static void device_send_reply(struct connman_device *device) +{ + if (device->pending_reply_list) { + g_list_foreach(device->pending_reply_list, __device_send_reply, NULL); + g_list_free(device->pending_reply_list); + device->pending_reply_list = NULL; + } +} +#endif + /** * connman_device_create: * @node: device node name (for example an address) @@ -464,55 +559,24 @@ struct connman_device *connman_device_create(const char *node, 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; } @@ -523,11 +587,13 @@ struct connman_device *connman_device_create(const char *node, * * 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; } @@ -538,9 +604,13 @@ struct connman_device *connman_device_ref(struct connman_device *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) { @@ -592,17 +662,6 @@ int connman_device_get_index(struct connman_device *device) 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 @@ -613,15 +672,12 @@ void __connman_device_set_phyindex(struct connman_device *device, 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); } @@ -637,6 +693,11 @@ void connman_device_set_interface(struct connman_device *device, void connman_device_set_ident(struct connman_device *device, const char *ident) { +#ifdef TIZEN_EXT + if (device->ident && device->powered) + return; + else +#endif g_free(device->ident); device->ident = g_strdup(ident); } @@ -654,122 +715,75 @@ const char *connman_device_get_ident(struct connman_device *device) * Change power state of device */ int connman_device_set_powered(struct connman_device *device, - connman_bool_t powered) + bool powered) { - int err; + 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) { - device->powered_pending = powered; + if (device->powered == powered) return -EALREADY; - } - if (powered == TRUE) - err = __connman_device_enable(device); - else - err = __connman_device_disable(device); +#if defined TIZEN_EXT + device_send_reply(device); +#endif + + clear_pending_trigger(device); - if (err < 0 && err != -EINPROGRESS && err != -EALREADY) - return err; + device->powered_pending = PENDING_NONE; device->powered = powered; - device->powered_pending = powered; type = __connman_device_get_service_type(device); - if (device->powered == TRUE) - __connman_technology_enable(type); - else - __connman_technology_disable(type); - - if (device->offlinemode == TRUE && powered == TRUE) - return connman_device_set_powered(device, FALSE); +#if defined TIZEN_EXT + device_send_changed(device->interface, type, "Powered", powered); +#endif - if (powered == FALSE) + if (!device->powered) { + __connman_technology_disabled(type); return 0; + } - reset_scan_trigger(device); - - if (device->driver && device->driver->scan) - device->driver->scan(device); - - return 0; -} - -int __connman_device_set_blocked(struct connman_device *device, - connman_bool_t blocked) -{ - connman_bool_t powered; - - DBG("device %p blocked %d", device, blocked); - - device->blocked = blocked; + __connman_technology_enabled(type); - if (device->offlinemode == TRUE) - return 0; + for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++) + device->scanning[i] = false; - connman_info("%s {rfkill} blocked %d", device->interface, blocked); + if (device->driver && device->driver->scan) { + memset(¶ms, 0, sizeof(params)); + params.type = CONNMAN_SERVICE_TYPE_UNKNOWN; - if (blocked == FALSE) - powered = device->powered_persistent; - else - powered = FALSE; + device->driver->scan(device, ¶ms); + } - return set_powered(device, powered); + return 0; } -connman_bool_t __connman_device_get_blocked(struct connman_device *device) +bool connman_device_get_powered(struct connman_device *device) { - return device->blocked; + return device->powered; } -static int device_scan(struct connman_device *device) +static int device_scan(enum connman_service_type type, + struct connman_device *device, + bool force_full_scan) { + struct connman_device_scan_params params; + 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) -{ - int err; - - DBG("device %p", device); - - device->powered_persistent = TRUE; - - __connman_storage_save_device(device); + memset(¶ms, 0, sizeof(params)); + params.type = type; + params.force_full_scan = force_full_scan; - err = __connman_device_enable(device); - if (err == 0 || err == -EINPROGRESS) { - device->offlinemode = FALSE; - if (__connman_profile_get_offlinemode() == TRUE) { - __connman_profile_set_offlinemode(FALSE, FALSE); - - __connman_profile_save_default(); - } - } - - return err; -} - -int __connman_device_disable_persistent(struct connman_device *device) -{ - DBG("device %p", device); - - device->powered_persistent = FALSE; - - __connman_storage_save_device(device); - - return __connman_device_disable(device); + return device->driver->scan(device, ¶ms); } int __connman_device_disconnect(struct connman_device *device) @@ -779,14 +793,12 @@ 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 @@ -808,130 +820,309 @@ int __connman_device_disconnect(struct connman_device *device) 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 (connman_network_get_connected(network) == TRUE) - return; + if (device->last_user_selection_time != time) { + device->last_user_selection_time = time; + return true; + } - connman_network_set_available(network, FALSE); + return false; } -static gboolean remove_unavailable_network(gpointer key, gpointer value, - gpointer user_data) +time_t connman_device_get_last_user_selection_time(struct connman_device *device) { - struct connman_network *network = value; + return device->last_user_selection_time; +} - if (connman_network_get_connected(network) == TRUE) - return FALSE; +bool connman_device_set_last_user_selection_ident(struct connman_device *device, + const char *ident) +{ + 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_available(network) == TRUE) - return FALSE; + return true; + } - return TRUE; + return false; } -void __connman_device_cleanup_networks(struct connman_device *device) +const char *connman_device_get_last_user_selection_ident(struct connman_device *device) { - g_hash_table_foreach_remove(device->networks, - remove_unavailable_network, NULL); + return device->last_user_selection_ident; } -connman_bool_t __connman_device_scanning(struct connman_device *device) +bool connman_device_set_last_connected_ident(struct connman_device *device, + const char *ident) { - return device->scanning; -} + if (g_strcmp0(device->last_connected_ident, ident) != 0) { + g_free(device->last_connected_ident); + device->last_connected_ident = g_strdup(ident); -void connman_device_reset_scanning(struct connman_device *device) -{ - device->scanning = FALSE; + return true; + } - g_hash_table_foreach(device->networks, - mark_network_available, NULL); + return false; +} +const char *connman_device_get_last_connected_ident(struct connman_device *device) +{ + return device->last_connected_ident; } -/** - * 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_save_last_user_selection(struct connman_device *device) { - DBG("device %p scanning %d", device, scanning); + GKeyFile *keyfile; + gchar *get_str; + gchar *selection_str; - if (!device->driver || !device->driver->scan) - return -EINVAL; + keyfile = __connman_storage_load_ins(); - if (device->scanning == scanning) - return -EALREADY; + selection_str = g_strdup_printf("%s:%ld", + device->last_user_selection_ident, device->last_user_selection_time); - device->scanning = scanning; + if (!keyfile) { + keyfile = g_key_file_new(); - if (scanning == TRUE) { - reset_scan_trigger(device); + g_key_file_set_string(keyfile, device->interface, "LastUserSelection", selection_str); + DBG("%s", selection_str); + __connman_storage_save_ins(keyfile); - g_hash_table_foreach(device->networks, - mark_network_unavailable, NULL); + } 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); + } - return 0; + g_free(get_str); } - __connman_device_cleanup_networks(device); + g_free(selection_str); + g_key_file_free(keyfile); +} - if (device->connections > 0) - return 0; +void connman_device_load_last_user_selection(struct connman_device *device) +{ + GKeyFile *keyfile; + gchar *get_str; + char **selection_str; - __connman_service_auto_connect(); + keyfile = __connman_storage_load_ins(); + if (!keyfile) + return; - return 0; + 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; + + /* 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); + + last_user_selection_time = strtol(selection_str[1], NULL, 10); + + 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]); + } + + device->last_user_selection_time = last_user_selection_time; + + DBG("%s %ld", device->last_user_selection_ident, device->last_user_selection_time); + } + + g_strfreev(selection_str); + } + + g_free(get_str); + } + + 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); +} + +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_get_disconnected: + * 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; } /** @@ -947,16 +1138,21 @@ int connman_device_set_string(struct connman_device *device, { DBG("device %p key %s value %s", device, key, value); - if (g_str_equal(key, "Address") == TRUE) { + if (g_str_equal(key, "Address")) { +#ifdef TIZEN_EXT + if (device->address && device->powered) + return 0; + else +#endif 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 { @@ -976,84 +1172,25 @@ int connman_device_set_string(struct connman_device *device, const char *connman_device_get_string(struct connman_device *device, const char *key) { +#if defined TIZEN_EXT + if (!simplified_log) +#endif 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; } -static void set_offlinemode(struct connman_device *device, - connman_bool_t offlinemode) -{ - connman_bool_t powered; - - DBG("device %p name %s", device, device->name); - - if (device == NULL) - return; - - device->offlinemode = offlinemode; - - if (device->blocked == TRUE) - return; - - powered = (offlinemode == TRUE) ? FALSE : TRUE; - - if (device->powered == powered) - return; - - if (device->powered_persistent == FALSE) - powered = FALSE; - - set_powered(device, powered); -} - -int __connman_device_set_offlinemode(connman_bool_t offlinemode) -{ - GSList *list; - - DBG("offlinmode %d", offlinemode); - - for (list = device_list; list != NULL; list = list->next) { - struct connman_device *device = list->data; - - set_offlinemode(device, offlinemode); - } - - __connman_notifier_offlinemode(offlinemode); - - return 0; -} - -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 @@ -1065,17 +1202,19 @@ int connman_device_add_network(struct connman_device *device, struct connman_network *network) { const char *identifier = connman_network_get_identifier(network); - +#if defined TIZEN_EXT + if (!simplified_log) +#endif 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; @@ -1091,11 +1230,62 @@ int connman_device_add_network(struct connman_device *device, struct connman_network *connman_device_get_network(struct connman_device *device, const char *identifier) { +#if defined TIZEN_EXT + if (!simplified_log) +#endif DBG("device %p identifier %s", device, identifier); 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_list = g_list_prepend(device->pending_reply_list, 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 @@ -1110,7 +1300,7 @@ int connman_device_remove_network(struct connman_device *device, DBG("device %p network %p", device, network); - if (network == NULL) + if (!network) return 0; identifier = connman_network_get_identifier(network); @@ -1119,23 +1309,18 @@ int connman_device_remove_network(struct connman_device *device, 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); @@ -1149,41 +1334,35 @@ void __connman_device_set_network(struct connman_device *device, } } -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); @@ -1194,35 +1373,10 @@ static int device_probe(struct connman_device *device) } } - 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); } /** @@ -1233,9 +1387,12 @@ int connman_device_register(struct connman_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); } /** @@ -1266,7 +1423,7 @@ struct connman_device *__connman_device_find_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); @@ -1280,214 +1437,784 @@ struct connman_device *__connman_device_find_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; - 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 0; - case CONNMAN_SERVICE_TYPE_WIFI: - case CONNMAN_SERVICE_TYPE_WIMAX: - 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) { - continue; - } - - err = device_scan(device); - if (err < 0 && err != -EINPROGRESS) { - DBG("err %d", err); - /* XXX maybe only a continue? */ - return err; - } + if (device->index == index) + return device; } - return 0; + 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); } -static int set_technology(enum connman_service_type type, connman_bool_t enable) +/** + * 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; - DBG("type %d enable %d", type, enable); - 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 0; - case CONNMAN_SERVICE_TYPE_ETHERNET: + return -EOPNOTSUPP; case CONNMAN_SERVICE_TYPE_WIFI: - case CONNMAN_SERVICE_TYPE_WIMAX: - case CONNMAN_SERVICE_TYPE_BLUETOOTH: - case CONNMAN_SERVICE_TYPE_CELLULAR: + 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); } + } - if (enable == TRUE) - err = __connman_device_enable_persistent(device); - else - err = __connman_device_disable_persistent(device); + if (success) + return 0; - if (err < 0 && err != -EINPROGRESS) { - DBG("err %d", err); - /* XXX maybe only a continue? */ - return err; + 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; } -int __connman_device_enable_technology(enum connman_service_type type) +#if defined TIZEN_EXT_WIFI_MESH +static int device_abort_scan(enum connman_service_type type, + struct connman_device *device) { - return set_technology(type, TRUE); + if (!device->driver || !device->driver->scan) + return -EOPNOTSUPP; + + 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; + + 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; } -int __connman_device_disable_technology(enum connman_service_type type) +static int device_mesh_specific_scan(enum connman_service_type type, + struct connman_device *device, const char *name, + unsigned int freq) { - return set_technology(type, FALSE); + 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); } -connman_bool_t __connman_device_isfiltered(const char *devname) +int __connman_device_request_mesh_specific_scan(enum connman_service_type type, + const char *name, + unsigned int freq) { - char **pattern; + bool success = false; + int last_err = -ENOSYS; + GSList *list; + int err; - if (device_filter == NULL) - goto nodevice; + 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; + } - for (pattern = device_filter; *pattern; pattern++) { - if (g_pattern_match_simple(*pattern, devname) == FALSE) { - DBG("ignoring device %s (match)", devname); - return TRUE; + 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); } } -nodevice: - if (g_pattern_match_simple("dummy*", devname) == TRUE) { - DBG("ignoring dummy networking devices"); - return TRUE; + if (success) + return 0; + + 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; } - if (nodevice_filter == NULL) - return FALSE; + for (list = device_list; list; list = list->next) { + struct connman_device *device = list->data; - for (pattern = nodevice_filter; *pattern; pattern++) { - if (g_pattern_match_simple(*pattern, devname) == TRUE) { - DBG("ignoring device %s (no match)", devname); - return TRUE; + 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 +#define WIFI_MAC "/opt/etc/.mac.info" +#define MAC_ADDR_LEN 18 + +char *_get_wifi_addr(void) { - const char *ident = __connman_profile_active_ident(); - GKeyFile *keyfile; - gchar *identifier; + FILE *fp = NULL; + char* rv = 0; + char wifi_mac[MAC_ADDR_LEN + 1]; + char *str; - DBG("device %p", device); + fp = fopen(WIFI_MAC, "r"); + if (!fp){ + connman_error("[%s] not present", WIFI_MAC); + return NULL; + } - keyfile = __connman_storage_open_profile(ident); - if (keyfile == NULL) - return 0; + rv = fgets(wifi_mac, MAC_ADDR_LEN, fp); + if (!rv) { + connman_error("Failed to get wifi mac address"); + fclose(fp); + return NULL; + } + + str = g_try_malloc0(MAC_ADDR_LEN); + if (!str) { + connman_error("memory allocation failed"); + fclose(fp); + return NULL; + } + + snprintf(str, MAC_ADDR_LEN, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", + g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]), + g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]), + g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]), + g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]), + g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]), + g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16])); + fclose(fp); + return str; +} + +char *_get_wifi_ident(void) +{ + FILE *fp = NULL; + char* rv = 0; + char wifi_mac[MAC_ADDR_LEN + 1]; + char *str; + + fp = fopen(WIFI_MAC, "r"); + if (!fp){ + connman_error("[%s] not present", WIFI_MAC); + return NULL; + } + + rv = fgets(wifi_mac, MAC_ADDR_LEN, fp); + if (!rv) { + connman_error("Failed to get wifi mac address"); + fclose(fp); + return NULL; + } + + str = g_try_malloc0(MAC_ADDR_LEN); + if (!str) { + connman_error("memory allocation failed"); + fclose(fp); + return NULL; + } + + snprintf(str, MAC_ADDR_LEN, "%c%c%c%c%c%c%c%c%c%c%c%c", + g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]), + g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]), + g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]), + g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]), + g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]), + g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16])); + fclose(fp); + return str; +} +#endif + +#if defined TIZEN_EXT +char *index2ident(int index, const char *prefix) +#else +static char *index2ident(int index, const char *prefix) +#endif +{ + struct ifreq ifr; + struct ether_addr eth; + char *str; + int sk, err, len; + + 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; + + 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]); - identifier = g_strdup_printf("device_%s", device->name); - if (identifier == NULL) + 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) @@ -1497,5 +2224,85 @@ 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 +} + +#ifdef TIZEN_EXT +void connman_device_mac_policy_notify(struct connman_device *device, + int result, unsigned int policy) +{ + device->mac_policy = policy; + __connman_technology_notify_mac_policy_by_device(device, result, policy); +} + +int connman_device_set_mac_policy(struct connman_device *device, + unsigned int policy) +{ + int err = 0; + + if (!device || !device->driver || !device->driver->set_mac_policy) + return -EOPNOTSUPP; + + device->mac_policy = policy; + err = device->driver->set_mac_policy(device, policy); + return err; +} + +unsigned int connman_device_get_mac_policy(struct connman_device *device) +{ + return device->mac_policy; +} + +void connman_device_preassoc_mac_policy_notify(struct connman_device *device, + int result, unsigned int policy) +{ + device->preassoc_mac_policy = policy; + __connman_technology_notify_preassoc_mac_policy_by_device(device, result, policy); +} + +int connman_device_set_preassoc_mac_policy(struct connman_device *device, + unsigned int policy) +{ + int err = 0; + + if (!device || !device->driver || !device->driver->set_preassoc_mac_policy) + return -EOPNOTSUPP; + + device->preassoc_mac_policy = policy; + err = device->driver->set_preassoc_mac_policy(device, policy); + return err; +} + +unsigned int connman_device_get_preassoc_mac_policy(struct connman_device *device) +{ + return device->preassoc_mac_policy; +} + +void connman_device_random_mac_lifetime_notify(struct connman_device *device, + int result, unsigned int lifetime) +{ + device->random_mac_lifetime = lifetime; + __connman_technology_notify_random_mac_lifetime_by_device(device, result, lifetime); } + +int connman_device_set_random_mac_lifetime(struct connman_device *device, + unsigned int lifetime) +{ + int err = 0; + + if (!device || !device->driver || !device->driver->set_random_mac_lifetime) + return -EOPNOTSUPP; + + device->random_mac_lifetime = lifetime; + err = device->driver->set_random_mac_lifetime(device, lifetime); + return err; +} + +unsigned int connman_device_get_random_mac_lifetime(struct connman_device *device) +{ + return device->random_mac_lifetime; +} + +#endif