X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdevice.c;h=75561c9f8046d92240d80429d9b5592413c7ce6f;hb=fe83d954f0a1a80e9e48008e0465edaaf0cd65ea;hp=b1d0a1bf4799a9932e16b8c1d24f821642c95fad;hpb=5196c97d9af6a1bdbf1f4d9689728b32c93d14c3;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/device.c b/src/device.c index b1d0a1b..d06bffd 100644 --- a/src/device.c +++ b/src/device.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,54 +26,52 @@ #include #include -#include - #include "connman.h" +static GSList *device_list = NULL; +static gchar **device_filter = NULL; +static gchar **nodevice_filter = NULL; + +enum connman_pending_type { + PENDING_NONE = 0, + PENDING_ENABLE = 1, + PENDING_DISABLE = 2, +}; + struct connman_device { - struct connman_element element; + int refcount; enum connman_device_type type; - enum connman_device_mode mode; - enum connman_device_policy policy; - connman_bool_t secondary; + enum connman_pending_type powered_pending; /* Indicates a pending + enable/disable request */ connman_bool_t powered; - connman_bool_t carrier; connman_bool_t scanning; connman_bool_t disconnected; - connman_uint16_t scan_interval; + connman_bool_t reconnect; char *name; char *node; char *address; char *interface; char *ident; - unsigned int connections; - guint scan_timeout; + char *path; + char *devname; + int phyindex; + int index; + guint pending_timeout; struct connman_device_driver *driver; void *driver_data; - connman_bool_t registered; - char *last_network; struct connman_network *network; GHashTable *networks; }; -static gboolean device_scan_trigger(gpointer user_data) +static void clear_pending_trigger(struct connman_device *device) { - struct connman_device *device = user_data; - - DBG("device %p", device); - - if (device->driver == NULL) { - device->scan_timeout = 0; - return FALSE; + if (device->pending_timeout > 0) { + g_source_remove(device->pending_timeout); + device->pending_timeout = 0; } - - if (device->driver->scan) - device->driver->scan(device); - - return TRUE; } static const char *type2description(enum connman_device_type type) @@ -92,11 +90,11 @@ static const char *type2description(enum connman_device_type type) return "Bluetooth"; case CONNMAN_DEVICE_TYPE_GPS: return "GPS"; - case CONNMAN_DEVICE_TYPE_HSO: - case CONNMAN_DEVICE_TYPE_NOZOMI: - case CONNMAN_DEVICE_TYPE_HUAWEI: - case CONNMAN_DEVICE_TYPE_NOVATEL: + case CONNMAN_DEVICE_TYPE_CELLULAR: return "Cellular"; + case CONNMAN_DEVICE_TYPE_GADGET: + return "Gadget"; + } return NULL; @@ -118,750 +116,180 @@ static const char *type2string(enum connman_device_type type) return "bluetooth"; case CONNMAN_DEVICE_TYPE_GPS: return "gps"; - case CONNMAN_DEVICE_TYPE_HSO: - case CONNMAN_DEVICE_TYPE_HUAWEI: - case CONNMAN_DEVICE_TYPE_NOZOMI: - case CONNMAN_DEVICE_TYPE_NOVATEL: + case CONNMAN_DEVICE_TYPE_CELLULAR: return "cellular"; - } + case CONNMAN_DEVICE_TYPE_GADGET: + return "gadget"; - return NULL; -} - -static const char *policy2string(enum connman_device_policy policy) -{ - switch (policy) { - case CONNMAN_DEVICE_POLICY_UNKNOWN: - break; - case CONNMAN_DEVICE_POLICY_IGNORE: - return "ignore"; - case CONNMAN_DEVICE_POLICY_OFF: - return "off"; - case CONNMAN_DEVICE_POLICY_AUTO: - return "auto"; - case CONNMAN_DEVICE_POLICY_MANUAL: - return "manual"; } return NULL; } -static enum connman_device_policy string2policy(const char *policy) -{ - if (g_str_equal(policy, "ignore") == TRUE) - return CONNMAN_DEVICE_POLICY_IGNORE; - else if (g_str_equal(policy, "off") == TRUE) - return CONNMAN_DEVICE_POLICY_OFF; - else if (g_str_equal(policy, "auto") == TRUE) - return CONNMAN_DEVICE_POLICY_AUTO; - else if (g_str_equal(policy, "manual") == TRUE) - return CONNMAN_DEVICE_POLICY_MANUAL; - else - return CONNMAN_DEVICE_POLICY_UNKNOWN; -} - -static int set_carrier(struct connman_device *device, connman_bool_t carrier) -{ - struct connman_service *service; - - service = __connman_service_lookup_from_device(device); - __connman_service_set_carrier(service, carrier); - - if (carrier == TRUE) { - enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN; - struct connman_element *element; - - device->disconnected = TRUE; - - switch (device->policy) { - case CONNMAN_DEVICE_POLICY_UNKNOWN: - case CONNMAN_DEVICE_POLICY_IGNORE: - case CONNMAN_DEVICE_POLICY_OFF: - case CONNMAN_DEVICE_POLICY_MANUAL: - return 0; - case CONNMAN_DEVICE_POLICY_AUTO: - break; - } - - switch (device->element.ipv4.method) { - case CONNMAN_IPV4_METHOD_UNKNOWN: - case CONNMAN_IPV4_METHOD_OFF: - return 0; - case CONNMAN_IPV4_METHOD_STATIC: - type = CONNMAN_ELEMENT_TYPE_IPV4; - break; - case CONNMAN_IPV4_METHOD_DHCP: - type = CONNMAN_ELEMENT_TYPE_DHCP; - break; - } - - element = connman_element_create(NULL); - if (element != NULL) { - element->type = type; - element->index = device->element.index; - - if (connman_element_register(element, - &device->element) < 0) - connman_element_unref(element); - - device->disconnected = FALSE; - - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_CONFIGURATION); - } - } else - connman_element_unregister_children(&device->element); - - return 0; -} - -static int set_powered(struct connman_device *device, connman_bool_t powered) +enum connman_service_type __connman_device_get_service_type(struct connman_device *device) { - struct connman_device_driver *driver = device->driver; - int err; - - DBG("device %p powered %d", device, powered); - - if (!driver) - return -EINVAL; + enum connman_device_type type = connman_device_get_type(device); - if (powered == TRUE) { - if (driver->enable) { - err = driver->enable(device); - __connman_notifier_device_type_increase(device->type); - } else - err = -EINVAL; - } else { - g_hash_table_remove_all(device->networks); - - set_carrier(device, FALSE); - - if (driver->disable) { - err = driver->disable(device); - __connman_notifier_device_type_decrease(device->type); - } else - err = -EINVAL; - } - - return err; -} - -static int set_policy(DBusConnection *connection, - struct connman_device *device, - enum connman_device_policy policy) -{ - DBusMessage *signal; - DBusMessageIter entry, value; - const char *str, *key = "Policy"; - int err = 0; - - DBG("device %p policy %d", device, policy); - - if (device->policy == policy) - return 0; - - switch (policy) { - case CONNMAN_DEVICE_POLICY_UNKNOWN: - return -EINVAL; - case CONNMAN_DEVICE_POLICY_IGNORE: - break; - case CONNMAN_DEVICE_POLICY_OFF: - if (device->powered == TRUE) - err = set_powered(device, FALSE); - break; - case CONNMAN_DEVICE_POLICY_AUTO: - case CONNMAN_DEVICE_POLICY_MANUAL: - if (device->powered == FALSE) - err = set_powered(device, TRUE); - else - err = set_carrier(device, device->carrier); - break; - } - - if (err < 0) - return err; - - device->policy = policy; - - signal = dbus_message_new_signal(device->element.path, - CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); - if (signal == NULL) - return 0; - - dbus_message_iter_init_append(signal, &entry); - - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); - - str = policy2string(policy); - - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_STRING_AS_STRING, &value); - dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str); - dbus_message_iter_close_container(&entry, &value); - - g_dbus_send_message(connection, signal); - - return 0; -} - -static void append_path(gpointer key, gpointer value, gpointer user_data) -{ - struct connman_element *element = value; - DBusMessageIter *iter = user_data; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, - &element->path); -} - -static void append_networks(struct connman_device *device, - DBusMessageIter *entry) -{ - DBusMessageIter value, iter; - const char *key = "Networks"; - - dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); - - dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, - &value); - - dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); - g_hash_table_foreach(device->networks, append_path, &iter); - dbus_message_iter_close_container(&value, &iter); - - dbus_message_iter_close_container(entry, &value); -} - -static DBusMessage *get_properties(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct connman_device *device = data; - DBusMessage *reply; - DBusMessageIter array, dict, entry; - const char *str; - - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0) - return __connman_error_permission_denied(msg); - - reply = dbus_message_new_method_return(msg); - if (reply == NULL) - return NULL; - - dbus_message_iter_init_append(reply, &array); - - dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - - if (device->name != NULL) - connman_dbus_dict_append_variant(&dict, "Name", - DBUS_TYPE_STRING, &device->name); - - str = type2string(device->type); - if (str != NULL) - connman_dbus_dict_append_variant(&dict, "Type", - DBUS_TYPE_STRING, &str); - - if (device->address != NULL) - connman_dbus_dict_append_variant(&dict, "Address", - DBUS_TYPE_STRING, &device->address); - - if (device->interface != NULL) - connman_dbus_dict_append_variant(&dict, "Interface", - DBUS_TYPE_STRING, &device->interface); - - str = policy2string(device->policy); - if (str != NULL) - connman_dbus_dict_append_variant(&dict, "Policy", - DBUS_TYPE_STRING, &str); - - connman_dbus_dict_append_variant(&dict, "Powered", - DBUS_TYPE_BOOLEAN, &device->powered); - - if (device->driver && device->driver->scan) - connman_dbus_dict_append_variant(&dict, "Scanning", - DBUS_TYPE_BOOLEAN, &device->scanning); - - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - break; - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - __connman_element_append_ipv4(&device->element, &dict); - break; - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - if (device->scan_interval > 0) - connman_dbus_dict_append_variant(&dict, "ScanInterval", - DBUS_TYPE_UINT16, &device->scan_interval); - - dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, - NULL, &entry); - append_networks(device, &entry); - dbus_message_iter_close_container(&dict, &entry); + switch (type) { + case CONNMAN_DEVICE_TYPE_UNKNOWN: + case CONNMAN_DEVICE_TYPE_VENDOR: + case CONNMAN_DEVICE_TYPE_GPS: break; - } - - dbus_message_iter_close_container(&array, &dict); - - return reply; -} - -static DBusMessage *set_property(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct connman_device *device = data; - DBusMessageIter iter, value; - const char *name; - int type; - - DBG("conn %p", conn); - - if (dbus_message_iter_init(msg, &iter) == FALSE) - return __connman_error_invalid_arguments(msg); - - dbus_message_iter_get_basic(&iter, &name); - dbus_message_iter_next(&iter); - dbus_message_iter_recurse(&iter, &value); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); - - type = dbus_message_iter_get_arg_type(&value); - - if (g_str_equal(name, "Powered") == TRUE) { - connman_bool_t powered; - int err; - - if (type != DBUS_TYPE_BOOLEAN) - return __connman_error_invalid_arguments(msg); - - dbus_message_iter_get_basic(&value, &powered); - - if (device->powered == powered) - return __connman_error_invalid_arguments(msg); - - err = set_powered(device, powered); - if (err < 0 && err != -EINPROGRESS) - return __connman_error_failed(msg, -err); - } else if (g_str_equal(name, "Policy") == TRUE) { - enum connman_device_policy policy; - const char *str; - int err; - - if (type != DBUS_TYPE_STRING) - return __connman_error_invalid_arguments(msg); - - dbus_message_iter_get_basic(&value, &str); - policy = string2policy(str); - if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN) - return __connman_error_invalid_arguments(msg); - - err = set_policy(conn, device, policy); - if (err < 0) - return __connman_error_failed(msg, -err); - } else if (g_str_equal(name, "ScanInterval") == TRUE) { - connman_uint16_t interval; - - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - return __connman_error_invalid_arguments(msg); - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - break; - } - - if (type != DBUS_TYPE_UINT16) - return __connman_error_invalid_arguments(msg); - - dbus_message_iter_get_basic(&value, &interval); - - device->scan_interval = interval; - - if (device->scan_timeout > 0) { - g_source_remove(device->scan_timeout); - device->scan_timeout = 0; - } - - if (device->scan_interval > 0) { - guint interval = device->scan_interval; - device->scan_timeout = g_timeout_add_seconds(interval, - device_scan_trigger, device); - } - } else if (g_str_has_prefix(name, "IPv4") == TRUE) { - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - return __connman_error_invalid_arguments(msg); - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - __connman_element_set_ipv4(&device->element, - name, &value); - break; - } - } - - __connman_storage_save_device(device); - - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); -} - -static char *build_group(const unsigned char *ssid, unsigned int ssid_len, - const char *mode, const char *security) -{ - GString *str; - unsigned int i; - - str = g_string_sized_new((ssid_len * 2) + 24); - if (str == NULL) - return NULL; - - if (ssid_len > 0 && ssid[0] != '\0') { - for (i = 0; i < ssid_len; i++) - g_string_append_printf(str, "%02x", ssid[i]); - } - - g_string_append_printf(str, "_%s_%s", mode, security); - - return g_string_free(str, FALSE); -} - -static DBusMessage *join_network(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct connman_device *device = data; - struct connman_network *network; - enum connman_network_type type; - unsigned int ssid_size; - const char *group, *mode, *security; - const void *ssid; - DBusMessageIter iter, array; - int err, index; - - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); - - if (!device->driver || !device->driver->join) - return __connman_error_not_supported(msg); - - dbus_message_iter_init(msg, &iter); - dbus_message_iter_recurse(&iter, &array); - - switch (device->type) { + case CONNMAN_DEVICE_TYPE_ETHERNET: + return CONNMAN_SERVICE_TYPE_ETHERNET; case CONNMAN_DEVICE_TYPE_WIFI: - type = CONNMAN_NETWORK_TYPE_WIFI; - break; - default: - return __connman_error_not_supported(msg); - } - - network = connman_network_create("00_00_00_00_00_00", type); - if (network == NULL) - return __connman_error_failed(msg, ENOMEM); - - while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) { - DBusMessageIter entry, value; - const char *key, *str; - - dbus_message_iter_recurse(&array, &entry); - dbus_message_iter_get_basic(&entry, &key); - - dbus_message_iter_next(&entry); - dbus_message_iter_recurse(&entry, &value); - - switch (dbus_message_iter_get_arg_type(&value)) { - case DBUS_TYPE_STRING: - dbus_message_iter_get_basic(&value, &str); - if (g_str_equal(key, "WiFi.SSID") == TRUE) - connman_network_set_blob(network, key, - str, strlen(str)); - else - connman_network_set_string(network, key, str); - break; - } + 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_CELLULAR; + case CONNMAN_DEVICE_TYPE_GADGET: + return CONNMAN_SERVICE_TYPE_GADGET; - dbus_message_iter_next(&array); } - ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_size); - mode = connman_network_get_string(network, "WiFi.Mode"); - security = connman_network_get_string(network, "WiFi.Security"); - group = build_group(ssid, ssid_size, mode, security); - - connman_network_set_group(network, group); - - index = connman_device_get_index(device); - connman_network_set_index(network, index); - - connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP); - - err = device->driver->join(device, network); - - connman_network_unref(network); - - if (err < 0) - return __connman_error_failed(msg, -err); - - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + return CONNMAN_SERVICE_TYPE_UNKNOWN; } -static DBusMessage *create_network(DBusConnection *conn, - DBusMessage *msg, void *data) +static gboolean device_pending_reset(gpointer user_data) { - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); - - return __connman_error_invalid_arguments(msg); -} + struct connman_device *device = user_data; -static DBusMessage *remove_network(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBG("conn %p", conn); + DBG("device %p", device); - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); + /* Power request timedout, reset power pending state. */ + device->pending_timeout = 0; + device->powered_pending = PENDING_NONE; - return __connman_error_invalid_arguments(msg); + return FALSE; } -static DBusMessage *propose_scan(DBusConnection *conn, - DBusMessage *msg, void *data) +int __connman_device_enable(struct connman_device *device) { - struct connman_device *device = data; int err; - DBG("conn %p", conn); - - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - return __connman_error_not_supported(msg); - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - break; - } - - if (!device->driver || !device->driver->scan) - return __connman_error_not_supported(msg); - - if (device->powered == FALSE) - return __connman_error_failed(msg, EINVAL); - - err = device->driver->scan(device); - if (err < 0) - return __connman_error_failed(msg, -err); - - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); -} - -static GDBusMethodTable device_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, - { "SetProperty", "sv", "", set_property }, - { "JoinNetwork", "a{sv}", "", join_network }, - { "CreateNetwork", "a{sv}", "o", create_network }, - { "RemoveNetwork", "o", "", remove_network }, - { "ProposeScan", "", "", propose_scan }, - { }, -}; - -static GDBusSignalTable device_signals[] = { - { "PropertyChanged", "sv" }, - { }, -}; - -static DBusConnection *connection; - -static void append_devices(DBusMessageIter *entry) -{ - DBusMessageIter value, iter; - const char *key = "Devices"; - - dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); - - dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, - &value); - - dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); - __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter); - dbus_message_iter_close_container(&value, &iter); - - dbus_message_iter_close_container(entry, &value); -} - -static void emit_devices_signal(void) -{ - DBusMessage *signal; - DBusMessageIter entry; - - signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); - if (signal == NULL) - return; + DBG("device %p", device); - dbus_message_iter_init_append(signal, &entry); + if (!device->driver || !device->driver->enable) + return -EOPNOTSUPP; - append_devices(&entry); + /* There is an ongoing power disable request. */ + if (device->powered_pending == PENDING_DISABLE) + return -EBUSY; - g_dbus_send_message(connection, signal); -} + if (device->powered_pending == PENDING_ENABLE) + return -EALREADY; -static int register_interface(struct connman_element *element) -{ - struct connman_device *device = element->device; + if (device->powered_pending == PENDING_NONE && device->powered == TRUE) + return -EALREADY; - DBG("element %p name %s", element, element->name); + device->powered_pending = PENDING_ENABLE; - if (g_dbus_register_interface(connection, element->path, - CONNMAN_DEVICE_INTERFACE, - device_methods, device_signals, - NULL, device, NULL) == FALSE) { - connman_error("Failed to register %s device", element->path); - return -EIO; + err = device->driver->enable(device); + /* + * device gets enabled right away. + * Invoke the callback + */ + if (err == 0) { + connman_device_set_powered(device, TRUE); + goto done; } - device->registered = TRUE; - - emit_devices_signal(); - - return 0; -} - -static void unregister_interface(struct connman_element *element) -{ - struct connman_device *device = element->device; - - DBG("element %p name %s", element, element->name); - - device->registered = FALSE; - - emit_devices_signal(); - - g_dbus_unregister_interface(connection, element->path, - CONNMAN_DEVICE_INTERFACE); -} - -static void device_enable(struct connman_device *device) -{ - DBG("device %p", device); - - if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE || - device->policy == CONNMAN_DEVICE_POLICY_OFF) - return; - - if (device->powered == TRUE) - return; - - if (device->driver->enable) { - device->driver->enable(device); - __connman_notifier_device_type_increase(device->type); + if (err == -EALREADY) { + /* If device is already powered, but connman is not updated */ + connman_device_set_powered(device, TRUE); + goto done; } + /* + * if err == -EINPROGRESS, then the DBus call to the respective daemon + * was successful. We set a 4 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(4, + device_pending_reset, device); +done: + return err; } -static void device_disable(struct connman_device *device) +int __connman_device_disable(struct connman_device *device) { + int err; + DBG("device %p", device); - if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE) - return; + if (!device->driver || !device->driver->disable) + return -EOPNOTSUPP; - if (device->powered == FALSE) - return; + /* Ongoing power enable request */ + if (device->powered_pending == PENDING_ENABLE) + return -EBUSY; - g_hash_table_remove_all(device->networks); + if (device->powered_pending == PENDING_DISABLE) + return -EALREADY; - if (device->driver->disable) { - device->driver->disable(device); - __connman_notifier_device_type_decrease(device->type); - } -} + if (device->powered_pending == PENDING_NONE && device->powered == FALSE) + return -EALREADY; -static int setup_device(struct connman_device *device) -{ - int err; + device->powered_pending = PENDING_DISABLE; + device->reconnect = FALSE; - DBG("device %p", device); + if (device->network) { + struct connman_service *service = + __connman_service_lookup_from_network(device->network); - err = register_interface(&device->element); - if (err < 0) { - if (device->driver->remove) - device->driver->remove(device); - device->driver = NULL; - return err; + if (service != NULL) + __connman_service_disconnect(service); + else + connman_network_set_connected(device->network, FALSE); } - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - break; - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - if (device->secondary == FALSE) - __connman_profile_add_device(device); - break; + err = device->driver->disable(device); + if (err == 0 || err == -EALREADY) { + connman_device_set_powered(device, FALSE); + goto done; } - device_enable(device); - - 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_element *element, gpointer user_data) +static void probe_driver(struct connman_device_driver *driver) { - struct connman_device_driver *driver = user_data; + GSList *list; - DBG("element %p name %s", element, element->name); + DBG("driver %p name %s", driver, driver->name); - if (element->device == NULL) - return; + for (list = device_list; list != NULL; list = list->next) { + struct connman_device *device = list->data; - if (element->device->driver != NULL) - return; + if (device->driver != NULL) + continue; - if (driver->type != element->device->type) - return; + if (driver->type != device->type) + continue; - if (driver->probe(element->device) < 0) - return; + if (driver->probe(device) < 0) + continue; - element->device->driver = driver; + device->driver = driver; - setup_device(element->device); + __connman_technology_add_device(device); + } } static void remove_device(struct connman_device *device) { DBG("device %p", device); - device_disable(device); + __connman_device_disable(device); - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - break; - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - if (device->secondary == FALSE) - __connman_profile_remove_device(device); - break; - } - - unregister_interface(&device->element); + __connman_technology_remove_device(device); if (device->driver->remove) device->driver->remove(device); @@ -869,17 +297,18 @@ static void remove_device(struct connman_device *device) device->driver = NULL; } -static void remove_driver(struct connman_element *element, gpointer user_data) +static void remove_driver(struct connman_device_driver *driver) { - struct connman_device_driver *driver = user_data; + GSList *list; - DBG("element %p name %s", element, element->name); + DBG("driver %p name %s", driver, driver->name); - if (element->device == NULL) - return; + for (list = device_list; list != NULL; list = list->next) { + struct connman_device *device = list->data; - if (element->device->driver == driver) - remove_device(element->device); + if (device->driver == driver) + remove_device(device); + } } connman_bool_t __connman_device_has_driver(struct connman_device *device) @@ -887,7 +316,7 @@ connman_bool_t __connman_device_has_driver(struct connman_device *device) if (device == NULL || device->driver == NULL) return FALSE; - return device->registered; + return TRUE; } static GSList *driver_list = NULL; @@ -914,9 +343,7 @@ int connman_device_driver_register(struct connman_device_driver *driver) driver_list = g_slist_insert_sorted(driver_list, driver, compare_priority); - - __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, - probe_driver, driver); + probe_driver(driver); return 0; } @@ -933,37 +360,40 @@ void connman_device_driver_unregister(struct connman_device_driver *driver) driver_list = g_slist_remove(driver_list, driver); - __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, - remove_driver, driver); + remove_driver(driver); } -static void unregister_network(gpointer data) +static void free_network(gpointer data) { struct connman_network *network = data; DBG("network %p", network); - connman_element_unregister((struct connman_element *) network); + __connman_network_set_device(network, NULL); connman_network_unref(network); } -static void device_destruct(struct connman_element *element) +static void device_destruct(struct connman_device *device) { - struct connman_device *device = element->device; + DBG("device %p name %s", device, device->name); - DBG("element %p name %s", element, element->name); + clear_pending_trigger(device); g_free(device->ident); g_free(device->node); g_free(device->name); 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; + + g_free(device); } /** @@ -979,7 +409,6 @@ struct connman_device *connman_device_create(const char *node, enum connman_device_type type) { struct connman_device *device; - const char *str; DBG("node %s type %d", node, type); @@ -989,55 +418,17 @@ struct connman_device *connman_device_create(const char *node, DBG("device %p", device); - __connman_element_initialize(&device->element); - - device->element.name = g_strdup(node); - device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE; - - device->element.device = device; - device->element.destruct = device_destruct; - - str = type2string(type); - if (str != NULL) - connman_element_set_string(&device->element, - CONNMAN_PROPERTY_ID_TYPE, str); + device->refcount = 1; - device->element.ipv4.method = CONNMAN_IPV4_METHOD_DHCP; + device->type = type; + device->name = g_strdup(type2description(device->type)); - device->type = type; - device->name = g_strdup(type2description(device->type)); - device->mode = CONNMAN_DEVICE_MODE_UNKNOWN; - device->policy = CONNMAN_DEVICE_POLICY_AUTO; - device->secondary = FALSE; - - switch (type) { - case CONNMAN_DEVICE_TYPE_UNKNOWN: - case CONNMAN_DEVICE_TYPE_VENDOR: - device->scan_interval = 0; - break; - case CONNMAN_DEVICE_TYPE_ETHERNET: - case CONNMAN_DEVICE_TYPE_WIFI: - device->scan_interval = 300; - break; - case CONNMAN_DEVICE_TYPE_WIMAX: - device->scan_interval = 0; - break; - case CONNMAN_DEVICE_TYPE_BLUETOOTH: - device->scan_interval = 0; - break; - case CONNMAN_DEVICE_TYPE_GPS: - device->scan_interval = 0; - break; - case CONNMAN_DEVICE_TYPE_HSO: - case CONNMAN_DEVICE_TYPE_NOZOMI: - case CONNMAN_DEVICE_TYPE_HUAWEI: - case CONNMAN_DEVICE_TYPE_NOVATEL: - device->scan_interval = 0; - break; - } + device->phyindex = -1; device->networks = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, unregister_network); + g_free, free_network); + + device_list = g_slist_append(device_list, device); return device; } @@ -1048,10 +439,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) { - if (connman_element_ref(&device->element) == NULL) - return NULL; + DBG("%p ref %d by %s:%d:%s()", device, device->refcount + 1, + file, line, caller); + + __sync_fetch_and_add(&device->refcount, 1); return device; } @@ -1062,9 +456,23 @@ 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) { - connman_element_unref(&device->element); + 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) { + device->driver->remove(device); + device->driver = NULL; + } + + device_list = g_slist_remove(device_list, device); + + device_destruct(device); } const char *__connman_device_get_type(struct connman_device *device) @@ -1084,28 +492,6 @@ enum connman_device_type connman_device_get_type(struct connman_device *device) } /** - * connman_device_get_name: - * @device: device structure - * - * Get unique name of device - */ -const char *connman_device_get_name(struct connman_device *device) -{ - return device->element.name; -} - -/** - * connman_device_get_path: - * @device: device structure - * - * Get path name of device - */ -const char *connman_device_get_path(struct connman_device *device) -{ - return device->element.path; -} - -/** * connman_device_set_index: * @device: device structure * @index: index number @@ -1114,7 +500,7 @@ const char *connman_device_get_path(struct connman_device *device) */ void connman_device_set_index(struct connman_device *device, int index) { - device->element.index = index; + device->index = index; } /** @@ -1125,7 +511,18 @@ void connman_device_set_index(struct connman_device *device, int index) */ int connman_device_get_index(struct connman_device *device) { - return device->element.index; + 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; } /** @@ -1136,10 +533,10 @@ int connman_device_get_index(struct connman_device *device) * Set interface name of device */ void connman_device_set_interface(struct connman_device *device, - const char *interface) + const char *interface) { - g_free(device->element.devname); - device->element.devname = g_strdup(interface); + g_free(device->devname); + device->devname = g_strdup(interface); g_free(device->interface); device->interface = g_strdup(interface); @@ -1153,17 +550,6 @@ void connman_device_set_interface(struct connman_device *device, } /** - * connman_device_get_interface: - * @device: device structure - * - * Get interface name of device - */ -const char *connman_device_get_interface(struct connman_device *device) -{ - return device->interface; -} - -/** * connman_device_set_ident: * @device: device structure * @ident: unique identifier @@ -1177,73 +563,12 @@ void connman_device_set_ident(struct connman_device *device, device->ident = g_strdup(ident); } -const char *__connman_device_get_ident(struct connman_device *device) +const char *connman_device_get_ident(struct connman_device *device) { return device->ident; } /** - * connman_device_set_policy: - * @device: device structure - * @policy: power and connection policy - * - * Change power and connection policy of device - */ -void connman_device_set_policy(struct connman_device *device, - enum connman_device_policy policy) -{ - device->policy = policy; -} - -/** - * connman_device_set_mode: - * @device: device structure - * @mode: network mode - * - * Change network mode of device - */ -void connman_device_set_mode(struct connman_device *device, - enum connman_device_mode mode) -{ - device->mode = mode; -} - -/** - * connman_device_get_mode: - * @device: device structure - * - * Get network mode of device - */ -enum connman_device_mode connman_device_get_mode(struct connman_device *device) -{ - return device->mode; -} - -/** - * connman_device_set_secondary: - * @device: device structure - * @secondary: secondary value - * - * Change secondary value of device - */ -void connman_device_set_secondary(struct connman_device *device, - connman_bool_t secondary) -{ - device->secondary = secondary; -} - -/** - * connman_device_get_secondary: - * @device: device structure - * - * Get secondary value of device - */ -connman_bool_t connman_device_get_secondary(struct connman_device *device) -{ - return device->secondary; -} - -/** * connman_device_set_powered: * @device: device structure * @powered: powered state @@ -1253,185 +578,92 @@ connman_bool_t connman_device_get_secondary(struct connman_device *device) int connman_device_set_powered(struct connman_device *device, connman_bool_t powered) { - DBusMessage *signal; - DBusMessageIter entry, value; - const char *key = "Powered"; + enum connman_service_type type; DBG("driver %p powered %d", device, powered); if (device->powered == powered) return -EALREADY; - device->powered = powered; - - if (device->registered == FALSE) - return 0; - - signal = dbus_message_new_signal(device->element.path, - CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); - if (signal == NULL) - return 0; - - dbus_message_iter_init_append(signal, &entry); + clear_pending_trigger(device); - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + device->powered_pending = PENDING_NONE; - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_BOOLEAN_AS_STRING, &value); - dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered); - dbus_message_iter_close_container(&entry, &value); + device->powered = powered; - g_dbus_send_message(connection, signal); + type = __connman_device_get_service_type(device); - if (powered == FALSE) + if (device->powered == FALSE) { + __connman_technology_disabled(type); return 0; - - if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) - return 0; - - if (device->scan_timeout > 0) { - g_source_remove(device->scan_timeout); - device->scan_timeout = 0; } - if (device->scan_interval > 0) { - guint interval = device->scan_interval; - device->scan_timeout = g_timeout_add_seconds(interval, - device_scan_trigger, device); - } + __connman_technology_enabled(type); - if (device->driver->scan) - device->driver->scan(device); - - return 0; -} + connman_device_set_disconnected(device, FALSE); + device->scanning = FALSE; -/** - * connman_device_set_carrier: - * @device: device structure - * @carrier: carrier state - * - * Change carrier state of device (only for device without scanning) - */ -int connman_device_set_carrier(struct connman_device *device, - connman_bool_t carrier) -{ - DBG("driver %p carrier %d", device, carrier); - - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - return -EINVAL; - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - break; - } - - if (device->carrier == carrier) - return -EALREADY; - - device->carrier = carrier; - - return set_carrier(device, device->carrier); -} - -int __connman_device_connect(struct connman_device *device) -{ - DBG("device %p", device); - - if (device->disconnected == FALSE) - return -EINVAL; - - if (device->driver && device->driver->connect) - device->driver->connect(device); + if (device->driver && device->driver->scan_fast) + device->driver->scan_fast(device); + else if (device->driver && device->driver->scan) + device->driver->scan(device); return 0; } -int __connman_device_disconnect(struct connman_device *device) -{ - GHashTableIter iter; - gpointer key, value; - - 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) { - struct connman_network *network = value; - - if (connman_network_get_connected(network) == TRUE) - __connman_network_disconnect(network); - } +static int device_scan(struct connman_device *device) +{ + if (!device->driver || !device->driver->scan) + return -EOPNOTSUPP; - if (device->driver && device->driver->disconnect) - device->driver->disconnect(device); + if (device->powered == FALSE) + return -ENOLINK; - return 0; + return device->driver->scan(device); } -static void connect_known_network(struct connman_device *device) +int __connman_device_disconnect(struct connman_device *device) { - struct connman_network *network = NULL; GHashTableIter iter; gpointer key, value; - const char *name; - unsigned int count = 0; 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) { - connman_uint8_t old_strength, new_strength; - - count++; - - if (connman_network_get_available(value) == FALSE) - continue; - - name = connman_network_get_string(value, - CONNMAN_PROPERTY_ID_NAME); - if (name != NULL && device->last_network != NULL) { - if (g_str_equal(name, device->last_network) == TRUE) { - network = value; - break; - } - } + struct connman_network *network = value; - if (network == NULL) { - network = value; + if (connman_network_get_connecting(network) == TRUE) { + /* + * Skip network in the process of connecting. + * This is a workaround for WiFi networks serviced + * by the supplicant plugin that hold a reference + * to the network. If we disconnect the network + * here then the referenced object will not be + * registered and usage (like launching DHCP client) + * will fail. There is nothing to be gained by + * removing the network here anyway. + */ + connman_warn("Skipping disconnect of %s, network is connecting.", + connman_network_get_identifier(network)); continue; } - old_strength = connman_network_get_uint8(network, - CONNMAN_PROPERTY_ID_STRENGTH); - new_strength = connman_network_get_uint8(value, - CONNMAN_PROPERTY_ID_STRENGTH); - - if (new_strength > old_strength) - network = value; + __connman_network_disconnect(network); } - if (network != NULL) { - int err; - - name = connman_network_get_string(value, - CONNMAN_PROPERTY_ID_NAME); - if (name != NULL) { - err = __connman_network_connect(network); - if (err == 0 || err == -EINPROGRESS) - return; - } - } + return 0; +} - if (count > 0) - return; +static void mark_network_available(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_network *network = value; - if (device->driver && device->driver->scan) - device->driver->scan(device); + connman_network_set_available(network, TRUE); } static void mark_network_unavailable(gpointer key, gpointer value, @@ -1459,6 +691,25 @@ static gboolean remove_unavailable_network(gpointer key, gpointer value, return TRUE; } +void __connman_device_cleanup_networks(struct connman_device *device) +{ + g_hash_table_foreach_remove(device->networks, + remove_unavailable_network, NULL); +} + +connman_bool_t connman_device_get_scanning(struct connman_device *device) +{ + return device->scanning; +} + +void connman_device_reset_scanning(struct connman_device *device) +{ + device->scanning = FALSE; + + g_hash_table_foreach(device->networks, + mark_network_available, NULL); +} + /** * connman_device_set_scanning: * @device: device structure @@ -1469,11 +720,7 @@ static gboolean remove_unavailable_network(gpointer key, gpointer value, int connman_device_set_scanning(struct connman_device *device, connman_bool_t scanning) { - DBusMessage *signal; - DBusMessageIter entry, value; - const char *key = "Scanning"; - - DBG("driver %p scanning %d", device, scanning); + DBG("device %p scanning %d", device, scanning); if (!device->driver || !device->driver->scan) return -EINVAL; @@ -1483,52 +730,20 @@ int connman_device_set_scanning(struct connman_device *device, device->scanning = scanning; - signal = dbus_message_new_signal(device->element.path, - CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); - if (signal == NULL) - return 0; - - dbus_message_iter_init_append(signal, &entry); - - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); - - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_BOOLEAN_AS_STRING, &value); - dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning); - dbus_message_iter_close_container(&entry, &value); - - g_dbus_send_message(connection, signal); - if (scanning == TRUE) { - if (device->scan_timeout > 0) { - g_source_remove(device->scan_timeout); - device->scan_timeout = 0; - } - - if (device->scan_interval > 0) { - guint interval = device->scan_interval; - device->scan_timeout = g_timeout_add_seconds(interval, - device_scan_trigger, device); - } + __connman_technology_scan_started(device); g_hash_table_foreach(device->networks, mark_network_unavailable, NULL); - return 0; - } - - g_hash_table_foreach_remove(device->networks, - remove_unavailable_network, NULL); - if (device->connections > 0) return 0; + } - if (device->disconnected == TRUE) - return 0; + __connman_device_cleanup_networks(device); - if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) - return 0; + __connman_technology_scan_stopped(device); - connect_known_network(device); + __connman_service_auto_connect(); return 0; } @@ -1543,16 +758,7 @@ int connman_device_set_scanning(struct connman_device *device, int connman_device_set_disconnected(struct connman_device *device, connman_bool_t disconnected) { - DBG("driver %p disconnected %d", device, disconnected); - - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - return -EINVAL; - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - break; - } + DBG("device %p disconnected %d", device, disconnected); if (device->disconnected == disconnected) return -EALREADY; @@ -1563,6 +769,17 @@ int connman_device_set_disconnected(struct connman_device *device, } /** + * connman_device_get_disconnected: + * @device: device structure + * + * Get device disconnected state + */ +connman_bool_t connman_device_get_disconnected(struct connman_device *device) +{ + return device->disconnected; +} + +/** * connman_device_set_string: * @device: device structure * @key: unique identifier @@ -1584,9 +801,14 @@ int connman_device_set_string(struct connman_device *device, } else if (g_str_equal(key, "Node") == TRUE) { g_free(device->node); device->node = g_strdup(value); + } else if (g_str_equal(key, "Path") == TRUE) { + g_free(device->path); + device->path = g_strdup(value); + } else { + return -EINVAL; } - return connman_element_set_string(&device->element, key, value); + return 0; } /** @@ -1607,49 +829,12 @@ const char *connman_device_get_string(struct connman_device *device, return device->name; else if (g_str_equal(key, "Node") == TRUE) return device->node; + else if (g_str_equal(key, "Interface") == TRUE) + return device->interface; + else if (g_str_equal(key, "Path") == TRUE) + return device->path; - return connman_element_get_string(&device->element, key); -} - -static void set_offlinemode(struct connman_element *element, gpointer user_data) -{ - struct connman_device *device = element->device; - connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data); - connman_bool_t powered; - - DBG("element %p name %s", element, element->name); - - if (device == NULL) - return; - - powered = (offlinemode == TRUE) ? FALSE : TRUE; - - if (device->powered == powered) - return; - - set_powered(device, powered); -} - -int __connman_device_set_offlinemode(connman_bool_t offlinemode) -{ - DBG("offlinmode %d", offlinemode); - - __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, - set_offlinemode, GUINT_TO_POINTER(offlinemode)); - - __connman_notifier_offline_mode(offlinemode); - - return 0; -} - -void __connman_device_increase_connections(struct connman_device *device) -{ - device->connections++; -} - -void __connman_device_decrease_connections(struct connman_device *device) -{ - device->connections--; + return NULL; } /** @@ -1663,31 +848,17 @@ int connman_device_add_network(struct connman_device *device, struct connman_network *network) { const char *identifier = connman_network_get_identifier(network); - int err; DBG("device %p network %p", device, network); - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + if (identifier == NULL) return -EINVAL; - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - break; - } - - __connman_network_set_device(network, device); - __connman_storage_load_network(network); + connman_network_ref(network); - err = connman_element_register((struct connman_element *) network, - &device->element); - if (err < 0) { - __connman_network_set_device(network, NULL); - return err; - } + __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; @@ -1716,33 +887,43 @@ struct connman_network *connman_device_get_network(struct connman_device *device * Remove network for given identifier */ int connman_device_remove_network(struct connman_device *device, - const char *identifier) + struct connman_network *network) { - DBG("device %p identifier %s", device, identifier); + const char *identifier; + + DBG("device %p network %p", device, network); + + if (network == NULL) + return 0; + identifier = connman_network_get_identifier(network); g_hash_table_remove(device->networks, identifier); 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->network == network) + if (device == NULL) return; - if (device->network != NULL) - connman_network_unref(device->network); + if (device->network == network) + return; if (network != NULL) { - name = connman_network_get_string(network, - CONNMAN_PROPERTY_ID_NAME); + name = connman_network_get_string(network, "Name"); g_free(device->last_network); device->last_network = g_strdup(name); - device->network = connman_network_ref(network); + device->network = network; } else { g_free(device->last_network); device->last_network = NULL; @@ -1751,6 +932,28 @@ 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, + struct connman_device_driver *driver) +{ + if (device->type == driver->type || + driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN) + return TRUE; + + return FALSE; +} + /** * connman_device_register: * @device: device structure @@ -1759,19 +962,31 @@ void __connman_device_set_network(struct connman_device *device, */ int connman_device_register(struct connman_device *device) { - __connman_storage_load_device(device); + GSList *list; - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - break; - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - __connman_storage_init_network(device); - break; + DBG("device %p name %s", device, device->name); + + if (device->driver != NULL) + return -EALREADY; + + for (list = driver_list; list; list = list->next) { + struct connman_device_driver *driver = list->data; + + if (match_driver(device, driver) == FALSE) + continue; + + DBG("driver %p name %s", driver, driver->name); + + if (driver->probe(device) == 0) { + device->driver = driver; + break; + } } - return connman_element_register(&device->element, NULL); + if (device->driver == NULL) + return 0; + + return __connman_technology_add_device(device); } /** @@ -1782,9 +997,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 == NULL) + return; - connman_element_unregister(&device->element); + remove_device(device); } /** @@ -1810,225 +1028,140 @@ void connman_device_set_data(struct connman_device *device, void *data) device->driver_data = data; } -static gboolean 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 FALSE; -} - -static int device_probe(struct connman_element *element) +struct connman_device *__connman_device_find_device( + enum connman_service_type type) { - struct connman_device *device = element->device; GSList *list; - DBG("element %p name %s", element, element->name); - - if (device == NULL) - return -ENODEV; - - if (device->driver != NULL) - return -EALREADY; - - for (list = driver_list; list; list = list->next) { - struct connman_device_driver *driver = list->data; + for (list = device_list; list != NULL; list = list->next) { + struct connman_device *device = list->data; + enum connman_service_type service_type = + __connman_device_get_service_type(device); - if (match_driver(device, driver) == FALSE) + if (service_type != type) continue; - DBG("driver %p name %s", driver, driver->name); - - if (driver->probe(device) == 0) { - device->driver = driver; - break; - } + return device; } - if (device->driver == NULL) - return -ENODEV; - - return setup_device(device); -} - -static void device_remove(struct connman_element *element) -{ - struct connman_device *device = element->device; - - DBG("element %p name %s", element, element->name); - - if (device == NULL) - return; - - if (device->driver == NULL) - return; - - remove_device(device); + return NULL; } -static struct connman_driver device_driver = { - .name = "device", - .type = CONNMAN_ELEMENT_TYPE_DEVICE, - .priority = CONNMAN_DRIVER_PRIORITY_LOW, - .probe = device_probe, - .remove = device_remove, -}; - -static int device_load(struct connman_device *device) +int __connman_device_request_scan(enum connman_service_type type) { - GKeyFile *keyfile; - gchar *pathname, *identifier, *data = NULL; - gsize length; - char *str; - int val; - - DBG("device %p", device); - - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, - __connman_profile_active_ident()); - if (pathname == NULL) - return -ENOMEM; - - keyfile = g_key_file_new(); - - if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) { - g_free(pathname); - return -ENOENT; - } - - g_free(pathname); + connman_bool_t success = FALSE; + int last_err = -ENOSYS; + GSList *list; + int err; - if (g_key_file_load_from_data(keyfile, data, length, - 0, NULL) == FALSE) { - g_free(data); - return -EILSEQ; + 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_WIMAX: + break; } - g_free(data); - - identifier = g_strdup_printf("device_%s", device->element.name); - if (identifier == NULL) - goto done; + for (list = device_list; list != NULL; list = list->next) { + struct connman_device *device = list->data; + enum connman_service_type service_type = + __connman_device_get_service_type(device); - str = g_key_file_get_string(keyfile, identifier, "Policy", NULL); - if (str != NULL) { - device->policy = string2policy(str); - g_free(str); - } + if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN && + service_type != type) { + continue; + } - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - break; - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - val = g_key_file_get_integer(keyfile, identifier, - "ScanInterval", NULL); - if (val > 0) - device->scan_interval = val; - break; + err = device_scan(device); + if (err == 0 || err == -EALREADY || err == -EINPROGRESS) { + success = TRUE; + } else { + last_err = err; + DBG("device %p err %d", device, err); + } } -done: - g_key_file_free(keyfile); - - g_free(identifier); + if (success == TRUE) + return 0; - return 0; + return last_err; } -static int device_save(struct connman_device *device) +int __connman_device_request_hidden_scan(struct connman_device *device, + const char *ssid, unsigned int ssid_len, + const char *identity, const char *passphrase, + void *user_data) { - GKeyFile *keyfile; - gchar *pathname, *identifier = NULL, *data = NULL; - gsize length; - const char *str; - DBG("device %p", device); - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, - __connman_profile_active_ident()); - if (pathname == NULL) - return -ENOMEM; - - keyfile = g_key_file_new(); - - if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) - goto update; + if (device == NULL || device->driver == NULL || + device->driver->scan_hidden == NULL) + return -EINVAL; - if (length > 0) { - if (g_key_file_load_from_data(keyfile, data, length, - 0, NULL) == FALSE) - goto done; - } + if (device->scanning == TRUE) + return -EALREADY; - g_free(data); + return device->driver->scan_hidden(device, ssid, ssid_len, + identity, passphrase, user_data); +} -update: - identifier = g_strdup_printf("device_%s", device->element.name); - if (identifier == NULL) - goto done; +connman_bool_t __connman_device_isfiltered(const char *devname) +{ + char **pattern; - str = policy2string(device->policy); - if (str != NULL) - g_key_file_set_string(keyfile, identifier, "Policy", str); + if (device_filter == NULL) + goto nodevice; - switch (device->mode) { - case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - break; - case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: - case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: - if (device->scan_interval > 0) - g_key_file_set_integer(keyfile, identifier, - "ScanInterval", device->scan_interval); - break; + for (pattern = device_filter; *pattern; pattern++) { + if (g_pattern_match_simple(*pattern, devname) == FALSE) { + DBG("ignoring device %s (match)", devname); + return TRUE; + } } - data = g_key_file_to_data(keyfile, &length, NULL); - - if (g_file_set_contents(pathname, data, length, NULL) == FALSE) - connman_error("Failed to store device information"); - -done: - g_free(data); +nodevice: + if (g_pattern_match_simple("dummy*", devname) == TRUE) { + DBG("ignoring dummy networking devices"); + return TRUE; + } - g_key_file_free(keyfile); + if (nodevice_filter == NULL) + return FALSE; - g_free(identifier); - g_free(pathname); + for (pattern = nodevice_filter; *pattern; pattern++) { + if (g_pattern_match_simple(*pattern, devname) == TRUE) { + DBG("ignoring device %s (no match)", devname); + return TRUE; + } + } - return 0; + return FALSE; } -static struct connman_storage device_storage = { - .name = "device", - .priority = CONNMAN_STORAGE_PRIORITY_LOW, - .device_load = device_load, - .device_save = device_save, -}; - -int __connman_device_init(void) +int __connman_device_init(const char *device, const char *nodevice) { DBG(""); - connection = connman_dbus_get_connection(); + if (device != NULL) + device_filter = g_strsplit(device, ",", -1); - if (connman_storage_register(&device_storage) < 0) - connman_error("Failed to register device storage"); + if (nodevice != NULL) + nodevice_filter = g_strsplit(nodevice, ",", -1); - return connman_driver_register(&device_driver); + return 0; } void __connman_device_cleanup(void) { DBG(""); - connman_driver_unregister(&device_driver); - - connman_storage_unregister(&device_storage); - - dbus_connection_unref(connection); + g_strfreev(nodevice_filter); + g_strfreev(device_filter); }