X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Felement.c;h=873a5f5fc51652ee956c2a201ceccbc815a0f085;hb=4f9a0637340e17790ad3c29546adc34ab6ce0362;hp=2934eddc786f793b5808d63ca635616cfb5c5b48;hpb=18886b7ef037884eff0bac7b9de673aa0a058493;p=connman diff --git a/src/element.c b/src/element.c index 2934edd..873a5f5 100644 --- a/src/element.c +++ b/src/element.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2009 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,7 @@ #include #include +#include #include #include @@ -33,17 +34,12 @@ static DBusConnection *connection; -static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT; static GNode *element_root = NULL; - static GSList *driver_list = NULL; - -static GThreadPool *thread_register = NULL; -static GThreadPool *thread_unregister = NULL; -static GThreadPool *thread_unregister_children = NULL; - static gchar *device_filter = NULL; +static gboolean started = FALSE; + static struct { enum connman_property_id id; int type; @@ -58,8 +54,16 @@ static struct { DBUS_TYPE_STRING, "IPv4.Netmask" }, { CONNMAN_PROPERTY_ID_IPV4_GATEWAY, DBUS_TYPE_STRING, "IPv4.Gateway" }, + { CONNMAN_PROPERTY_ID_IPV4_BROADCAST, + DBUS_TYPE_STRING, "IPv4.Broadcast" }, { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, DBUS_TYPE_STRING, "IPv4.Nameserver" }, + + { CONNMAN_PROPERTY_ID_WIFI_SECURITY, + DBUS_TYPE_STRING, "WiFi.Security" }, + { CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE, + DBUS_TYPE_STRING, "WiFi.Passphrase" }, + { } }; @@ -94,10 +98,16 @@ static const char *type2string(enum connman_element_type type) return "unknown"; case CONNMAN_ELEMENT_TYPE_ROOT: return "root"; + case CONNMAN_ELEMENT_TYPE_PROFILE: + return "profile"; case CONNMAN_ELEMENT_TYPE_DEVICE: return "device"; case CONNMAN_ELEMENT_TYPE_NETWORK: return "network"; + case CONNMAN_ELEMENT_TYPE_SERVICE: + return "service"; + case CONNMAN_ELEMENT_TYPE_PPP: + return "ppp"; case CONNMAN_ELEMENT_TYPE_IPV4: return "ipv4"; case CONNMAN_ELEMENT_TYPE_IPV6: @@ -108,10 +118,10 @@ static const char *type2string(enum connman_element_type type) return "bootp"; case CONNMAN_ELEMENT_TYPE_ZEROCONF: return "zeroconf"; - case CONNMAN_ELEMENT_TYPE_RESOLVER: - return "resolver"; - case CONNMAN_ELEMENT_TYPE_INTERNET: - return "internet"; + case CONNMAN_ELEMENT_TYPE_CONNECTION: + return "connection"; + case CONNMAN_ELEMENT_TYPE_VENDOR: + return "vendor"; } return NULL; @@ -122,16 +132,16 @@ static const char *subtype2string(enum connman_element_subtype type) switch (type) { case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN: return "unknown"; - case CONNMAN_ELEMENT_SUBTYPE_NETWORK: - return "network"; + case CONNMAN_ELEMENT_SUBTYPE_FAKE: + return "fake"; case CONNMAN_ELEMENT_SUBTYPE_ETHERNET: return "ethernet"; case CONNMAN_ELEMENT_SUBTYPE_WIFI: return "wifi"; case CONNMAN_ELEMENT_SUBTYPE_WIMAX: return "wimax"; - case CONNMAN_ELEMENT_SUBTYPE_MODEM: - return "modem"; + case CONNMAN_ELEMENT_SUBTYPE_CELLULAR: + return "cellular"; case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH: return "bluetooth"; } @@ -139,44 +149,60 @@ static const char *subtype2string(enum connman_element_subtype type) return NULL; } -static void append_entry(DBusMessageIter *dict, - const char *key, int type, void *val) +const char *__connman_element_policy2string(enum connman_element_policy policy) { - DBusMessageIter entry, value; - const char *signature; + switch (policy) { + case CONNMAN_ELEMENT_POLICY_UNKNOWN: + return "unknown"; + case CONNMAN_ELEMENT_POLICY_IGNORE: + return "ignore"; + case CONNMAN_ELEMENT_POLICY_AUTO: + return "auto"; + case CONNMAN_ELEMENT_POLICY_ASK: + return "ask"; + } - dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, - NULL, &entry); + return NULL; +} - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); +enum connman_element_policy __connman_element_string2policy(const char *policy) +{ + if (strcasecmp(policy, "ignore") == 0) + return CONNMAN_ELEMENT_POLICY_IGNORE; + else if (strcasecmp(policy, "auto") == 0) + return CONNMAN_ELEMENT_POLICY_AUTO; + else if (strcasecmp(policy, "ask") == 0) + return CONNMAN_ELEMENT_POLICY_ASK; + else + return CONNMAN_ELEMENT_POLICY_UNKNOWN; +} - switch (type) { - case DBUS_TYPE_BOOLEAN: - signature = DBUS_TYPE_BOOLEAN_AS_STRING; - break; - case DBUS_TYPE_STRING: - signature = DBUS_TYPE_STRING_AS_STRING; - break; - case DBUS_TYPE_UINT16: - signature = DBUS_TYPE_UINT16_AS_STRING; - break; - case DBUS_TYPE_UINT32: - signature = DBUS_TYPE_UINT32_AS_STRING; - break; - case DBUS_TYPE_OBJECT_PATH: - signature = DBUS_TYPE_OBJECT_PATH_AS_STRING; - break; - default: - signature = DBUS_TYPE_VARIANT_AS_STRING; - break; +const char *__connman_ipv4_method2string(enum connman_ipv4_method method) +{ + switch (method) { + case CONNMAN_IPV4_METHOD_UNKNOWN: + return "unknown"; + case CONNMAN_IPV4_METHOD_OFF: + return "off"; + case CONNMAN_IPV4_METHOD_STATIC: + return "static"; + case CONNMAN_IPV4_METHOD_DHCP: + return "dhcp"; } - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - signature, &value); - dbus_message_iter_append_basic(&value, type, val); - dbus_message_iter_close_container(&entry, &value); + return "unknown"; +} - dbus_message_iter_close_container(dict, &entry); +enum connman_ipv4_method __connman_ipv4_string2method(const char *method) +{ + if (strcasecmp(method, "off") == 0) + return CONNMAN_IPV4_METHOD_OFF; + else if (strcasecmp(method, "static") == 0) + return CONNMAN_IPV4_METHOD_STATIC; + else if (strcasecmp(method, "dhcp") == 0) + return CONNMAN_IPV4_METHOD_DHCP; + else + return CONNMAN_IPV4_METHOD_UNKNOWN; } static void append_property(DBusMessageIter *dict, @@ -185,101 +211,85 @@ static void append_property(DBusMessageIter *dict, if (property->value == NULL) return; - append_entry(dict, property->name, property->type, &property->value); + switch (property->type) { + case DBUS_TYPE_ARRAY: + connman_dbus_dict_append_array(dict, property->name, + property->subtype, &property->value, property->size); + break; + case DBUS_TYPE_STRING: + connman_dbus_dict_append_variant(dict, property->name, + property->type, &property->value); + break; + default: + connman_dbus_dict_append_variant(dict, property->name, + property->type, property->value); + break; + } } -static DBusMessage *get_properties(DBusConnection *conn, - DBusMessage *msg, void *data) +static void add_common_properties(struct connman_element *element, + DBusMessageIter *dict) { - struct connman_element *element = data; + const char *address = NULL, *netmask = NULL, *gateway = NULL; GSList *list; - DBusMessage *reply; - DBusMessageIter array, dict; - const char *str; - - DBG("conn %p", conn); - - 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 (element->parent != NULL && - element->parent->type != CONNMAN_ELEMENT_TYPE_ROOT) { - append_entry(&dict, "Parent", - DBUS_TYPE_OBJECT_PATH, &element->parent->path); - } - - str = type2string(element->type); - if (str != NULL) - append_entry(&dict, "Type", DBUS_TYPE_STRING, &str); - str = subtype2string(element->subtype); - if (str != NULL) - append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str); - - append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &element->enabled); + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address); + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask); + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); if (element->priority > 0) - append_entry(&dict, "Priority", - DBUS_TYPE_UINT16, &element->priority); - - if (element->network.identifier != NULL) - append_entry(&dict, "Identifier", - DBUS_TYPE_STRING, &element->network.identifier); - - if (element->ipv4.address != NULL) - append_entry(&dict, "IPv4.Address", - DBUS_TYPE_STRING, &element->ipv4.address); - if (element->ipv4.netmask != NULL) - append_entry(&dict, "IPv4.Netmask", - DBUS_TYPE_STRING, &element->ipv4.netmask); - if (element->ipv4.gateway != NULL) - append_entry(&dict, "IPv4.Gateway", - DBUS_TYPE_STRING, &element->ipv4.gateway); + connman_dbus_dict_append_variant(dict, "Priority", + DBUS_TYPE_UINT16, &element->priority); + + if (address != NULL) + connman_dbus_dict_append_variant(dict, "IPv4.Address", + DBUS_TYPE_STRING, &address); + if (netmask != NULL) + connman_dbus_dict_append_variant(dict, "IPv4.Netmask", + DBUS_TYPE_STRING, &netmask); + if (gateway != NULL) + connman_dbus_dict_append_variant(dict, "IPv4.Gateway", + DBUS_TYPE_STRING, &gateway); + + if (element->wifi.security != NULL) { + const char *passphrase = ""; + + connman_dbus_dict_append_variant(dict, "WiFi.Security", + DBUS_TYPE_STRING, &element->wifi.security); + + if (element->wifi.passphrase != NULL) + passphrase = element->wifi.passphrase; + + connman_dbus_dict_append_variant(dict, "WiFi.Passphrase", + DBUS_TYPE_STRING, &passphrase); + } - connman_element_lock(element); + __connman_element_lock(element); for (list = element->properties; list; list = list->next) { struct connman_property *property = list->data; - append_property(&dict, property); + append_property(dict, property); } - connman_element_unlock(element); - - dbus_message_iter_close_container(&array, &dict); - - return reply; + __connman_element_unlock(element); } -static DBusMessage *set_property(DBusConnection *conn, - DBusMessage *msg, void *data) +#if 0 +static void set_common_property(struct connman_element *element, + const char *name, DBusMessageIter *value) { - struct connman_element *element = data; - DBusMessageIter iter; - DBusMessageIter value; - const char *name; GSList *list; - 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_privileges(msg) < 0) - return __connman_error_permission_denied(msg); + if (g_str_equal(name, "Priority") == TRUE) { + dbus_message_iter_get_basic(value, &element->priority); + return; + } - connman_element_lock(element); + __connman_element_lock(element); for (list = element->properties; list; list = list->next) { struct connman_property *property = list->data; @@ -294,122 +304,204 @@ static DBusMessage *set_property(DBusConnection *conn, property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE; if (property->type == DBUS_TYPE_STRING) { - dbus_message_iter_get_basic(&value, &str); + dbus_message_iter_get_basic(value, &str); g_free(property->value); property->value = g_strdup(str); } else property->value = NULL; } - connman_element_unlock(element); + __connman_element_unlock(element); +} +#endif - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +static void emit_element_signal(DBusConnection *conn, const char *member, + struct connman_element *element) +{ + DBusMessage *signal; + + if (__connman_debug_enabled() == FALSE) + return; + + DBG("conn %p member %s", conn, member); + + if (element == NULL) + return; + + signal = dbus_message_new_signal(element->path, + CONNMAN_DEBUG_INTERFACE, member); + if (signal == NULL) + return; + + g_dbus_send_message(conn, signal); } -static DBusMessage *clear_property(DBusConnection *conn, - DBusMessage *msg, void *data) +static void emit_enabled_signal(DBusConnection *conn, + struct connman_element *element) { - struct connman_element *element = data; - const char *name; - GSList *list; + DBusMessage *signal; + DBusMessageIter entry, value; + const char *iface, *key; DBG("conn %p", conn); - if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID) == FALSE) - return __connman_error_invalid_arguments(msg); + if (element == NULL) + return; - if (__connman_security_check_privileges(msg) < 0) - return __connman_error_permission_denied(msg); + switch (element->type) { + case CONNMAN_ELEMENT_TYPE_CONNECTION: + iface = CONNMAN_CONNECTION_INTERFACE; + key = "Default"; + break; + default: + return; + } - connman_element_lock(element); + signal = dbus_message_new_signal(element->path, + iface, "PropertyChanged"); + if (signal == NULL) + return; - for (list = element->properties; list; list = list->next) { - struct connman_property *property = list->data; + dbus_message_iter_init_append(signal, &entry); - if (g_str_equal(property->name, name) == FALSE) - continue; + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); - if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) - continue; + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_BOOLEAN_AS_STRING, &value); + dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, + &element->enabled); + dbus_message_iter_close_container(&entry, &value); - if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE) - continue; + g_dbus_send_message(conn, signal); +} + +static DBusMessage *do_enable(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_element *element = data; - property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE; + DBG("conn %p", conn); - if (property->type == DBUS_TYPE_STRING) - g_free(property->value); + if (element->enabled == TRUE) + return __connman_error_failed(msg); - property->value = NULL; + if (element->driver && element->driver->enable) { + DBG("Calling enable callback"); + if (element->driver->enable(element) < 0) + return __connman_error_failed(msg); } - connman_element_unlock(element); + element->enabled = TRUE; + + emit_enabled_signal(connection, element); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static DBusMessage *do_update(DBusConnection *conn, +static DBusMessage *do_disable(DBusConnection *conn, DBusMessage *msg, void *data) { struct connman_element *element = data; DBG("conn %p", conn); - if (element->driver == NULL) - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + if (element->enabled == FALSE) + return __connman_error_failed(msg); - if (element->driver->update) { - DBG("Calling update callback"); - element->driver->update(element); + if (element->driver && element->driver->disable) { + DBG("Calling disable callback"); + if (element->driver->disable(element) < 0) + return __connman_error_failed(msg); } + element->enabled = FALSE; + + emit_enabled_signal(connection, element); + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static DBusMessage *do_enable(DBusConnection *conn, +static DBusMessage *connection_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct connman_element *element = data; + DBusMessage *reply; + DBusMessageIter array, dict; + const char *str; DBG("conn %p", conn); - if (element->driver == NULL) - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + reply = dbus_message_new_method_return(msg); + if (reply == NULL) + return NULL; - if (element->driver->enable) { - DBG("Calling enable callback"); - element->driver->enable(element); - } + dbus_message_iter_init_append(reply, &array); - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + 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); + + str = subtype2string(element->subtype); + if (str != NULL) + connman_dbus_dict_append_variant(&dict, "Type", + DBUS_TYPE_STRING, &str); + + if (element->devname != NULL) + connman_dbus_dict_append_variant(&dict, "Interface", + DBUS_TYPE_STRING, &element->devname); + + if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIFI || + element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIMAX) + connman_dbus_dict_append_variant(&dict, "Strength", + DBUS_TYPE_BYTE, &element->strength); + + connman_dbus_dict_append_variant(&dict, "Default", + DBUS_TYPE_BOOLEAN, &element->enabled); + + add_common_properties(element, &dict); + + dbus_message_iter_close_container(&array, &dict); + + return reply; } -static DBusMessage *do_disable(DBusConnection *conn, +static DBusMessage *connection_set_property(DBusConnection *conn, DBusMessage *msg, void *data) { struct connman_element *element = data; + DBusMessageIter iter, value; + const char *name; DBG("conn %p", conn); - if (element->driver == NULL) - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + if (dbus_message_iter_init(msg, &iter) == FALSE) + return __connman_error_invalid_arguments(msg); - if (element->driver->disable) { - DBG("Calling disable callback"); - element->driver->disable(element); + dbus_message_iter_get_basic(&iter, &name); + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &value); + + if (__connman_security_check_privileges(msg) < 0) + return __connman_error_permission_denied(msg); + + if (g_str_equal(name, "Default") == TRUE) { + dbus_bool_t enabled; + + dbus_message_iter_get_basic(&value, &enabled); + + if (enabled == TRUE) + return do_enable(conn, msg, element); + else + return do_disable(conn, msg, element); } return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static GDBusMethodTable element_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, - { "SetProperty", "sv", "", set_property }, - { "ClearProperty", "s", "", clear_property }, - { "Update", "", "", do_update }, - { "Enable", "", "", do_enable }, - { "Disable", "", "", do_disable }, +static GDBusMethodTable connection_methods[] = { + { "GetProperties", "", "a{sv}", connection_get_properties }, + { "SetProperty", "sv", "", connection_set_property }, { }, }; @@ -418,15 +510,62 @@ static GDBusSignalTable element_signals[] = { { }, }; +struct foreach_data { + enum connman_element_type type; + element_cb_t callback; + gpointer user_data; +}; + +static gboolean foreach_callback(GNode *node, gpointer user_data) +{ + struct connman_element *element = node->data; + struct foreach_data *data = user_data; + + DBG("element %p name %s", element, element->name); + + if (element->type == CONNMAN_ELEMENT_TYPE_ROOT) + return FALSE; + + if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN && + data->type != element->type) + return FALSE; + + if (data->callback) + data->callback(element, data->user_data); + + return FALSE; +} + +void __connman_element_foreach(struct connman_element *element, + enum connman_element_type type, + element_cb_t callback, gpointer user_data) +{ + struct foreach_data data = { type, callback, user_data }; + GNode *node; + + DBG(""); + + if (element != NULL) { + node = g_node_find(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, element); + if (node == NULL) + return; + } else + node = element_root; + + g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + foreach_callback, &data); +} + struct append_filter { enum connman_element_type type; DBusMessageIter *iter; }; -static gboolean append_path(GNode *node, gpointer data) +static gboolean append_path(GNode *node, gpointer user_data) { struct connman_element *element = node->data; - struct append_filter *filter = data; + struct append_filter *filter = user_data; DBG("element %p name %s", element, element->name); @@ -437,23 +576,85 @@ static gboolean append_path(GNode *node, gpointer data) filter->type != element->type) return FALSE; + if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE && + __connman_device_has_driver(element->device) == FALSE) + return FALSE; + + if (filter->type == CONNMAN_ELEMENT_TYPE_NETWORK && + __connman_network_has_driver(element->network) == FALSE) + return FALSE; + dbus_message_iter_append_basic(filter->iter, DBUS_TYPE_OBJECT_PATH, &element->path); return FALSE; } -void __connman_element_list(enum connman_element_type type, - DBusMessageIter *iter) +void __connman_element_list(struct connman_element *element, + enum connman_element_type type, + DBusMessageIter *iter) { struct append_filter filter = { type, iter }; + GNode *node; DBG(""); - g_static_rw_lock_reader_lock(&element_lock); - g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - append_path, &filter); - g_static_rw_lock_reader_unlock(&element_lock); + if (element != NULL) { + node = g_node_find(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, element); + if (node == NULL) + return; + } else + node = element_root; + + g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + append_path, &filter); +} + +struct count_data { + enum connman_element_type type; + int count; +}; + +static gboolean count_element(GNode *node, gpointer user_data) +{ + struct connman_element *element = node->data; + struct count_data *data = user_data; + + DBG("element %p name %s", element, element->name); + + if (element->type == CONNMAN_ELEMENT_TYPE_ROOT) + return FALSE; + + if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN && + data->type != element->type) + return FALSE; + + data->count++; + + return FALSE; +} + +int __connman_element_count(struct connman_element *element, + enum connman_element_type type) +{ + struct count_data data = { type, 0 }; + GNode *node; + + DBG(""); + + if (element != NULL) { + node = g_node_find(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, element); + if (node == NULL) + return 0; + } else + node = element_root; + + g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + count_element, &data); + + return data.count; } static gint compare_priority(gconstpointer a, gconstpointer b) @@ -481,6 +682,22 @@ static gboolean match_driver(struct connman_element *element, return FALSE; } +static void enable_element(struct connman_element *element) +{ + if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE) + return; + + if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO) + return; + + if (element->driver && element->driver->enable) { + if (element->driver->enable(element) == 0) { + element->enabled = TRUE; + emit_enabled_signal(connection, element); + } + } +} + static gboolean probe_driver(GNode *node, gpointer data) { struct connman_element *element = node->data; @@ -492,15 +709,29 @@ static gboolean probe_driver(GNode *node, gpointer data) if (driver->probe(element) < 0) return FALSE; - connman_element_lock(element); + __connman_element_lock(element); element->driver = driver; - connman_element_unlock(element); + __connman_element_unlock(element); + + enable_element(element); } return FALSE; } -/** +void __connman_driver_rescan(struct connman_driver *driver) +{ + DBG("driver %p name %s", driver, driver->name); + + if (!driver->probe) + return; + + if (element_root != NULL) + g_node_traverse(element_root, G_PRE_ORDER, + G_TRAVERSE_ALL, -1, probe_driver, driver); +} + +/** * connman_driver_register: * @driver: driver definition * @@ -518,20 +749,35 @@ int connman_driver_register(struct connman_driver *driver) if (!driver->probe) return -EINVAL; - g_static_rw_lock_writer_lock(&element_lock); - driver_list = g_slist_insert_sorted(driver_list, driver, compare_priority); + if (started == FALSE) + return 0; + if (element_root != NULL) g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, probe_driver, driver); - g_static_rw_lock_writer_unlock(&element_lock); - return 0; } +static void disable_element(struct connman_element *element) +{ + if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO) + return; + + if (element->enabled == FALSE) + return; + + if (element->driver && element->driver->disable) { + if (element->driver->disable(element) == 0) { + element->enabled = FALSE; + emit_enabled_signal(connection, element); + } + } +} + static gboolean remove_driver(GNode *node, gpointer data) { struct connman_element *element = node->data; @@ -540,12 +786,14 @@ static gboolean remove_driver(GNode *node, gpointer data) DBG("element %p name %s", element, element->name); if (element->driver == driver) { + disable_element(element); + if (driver->remove) driver->remove(element); - connman_element_lock(element); + __connman_element_lock(element); element->driver = NULL; - connman_element_unlock(element); + __connman_element_unlock(element); } return FALSE; @@ -561,15 +809,11 @@ void connman_driver_unregister(struct connman_driver *driver) { DBG("driver %p name %s", driver, driver->name); - g_static_rw_lock_writer_lock(&element_lock); - driver_list = g_slist_remove(driver_list, driver); if (element_root != NULL) g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, remove_driver, driver); - - g_static_rw_lock_writer_unlock(&element_lock); } /** @@ -593,12 +837,11 @@ struct connman_element *connman_element_create(const char *name) element->refcount = 1; - g_static_mutex_init(&element->mutex); - element->name = g_strdup(name); element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN; element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN; element->state = CONNMAN_ELEMENT_STATE_CLOSED; + element->policy = CONNMAN_ELEMENT_POLICY_AUTO; element->index = -1; element->enabled = FALSE; @@ -621,16 +864,15 @@ static void free_properties(struct connman_element *element) DBG("element %p name %s", element, element->name); - connman_element_lock(element); + __connman_element_lock(element); for (list = element->properties; list; list = list->next) { struct connman_property *property = list->data; - if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) { - if (property->type == DBUS_TYPE_STRING) - g_free(property->value); - } + if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) + g_free(property->value); + g_free(property->name); g_free(property); } @@ -638,7 +880,7 @@ static void free_properties(struct connman_element *element) element->properties = NULL; - connman_element_unlock(element); + __connman_element_unlock(element); } void connman_element_unref(struct connman_element *element) @@ -647,6 +889,8 @@ void connman_element_unref(struct connman_element *element) g_atomic_int_get(&element->refcount) - 1); if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) { + if (element->destruct) + element->destruct(element); free_properties(element); g_free(element->ipv4.address); g_free(element->ipv4.netmask); @@ -654,7 +898,8 @@ void connman_element_unref(struct connman_element *element) g_free(element->ipv4.network); g_free(element->ipv4.broadcast); g_free(element->ipv4.nameserver); - g_free(element->network.identifier); + g_free(element->devname); + g_free(element->devpath); g_free(element->path); g_free(element->name); g_free(element); @@ -668,7 +913,7 @@ int connman_element_add_static_property(struct connman_element *element, DBG("element %p name %s", element, element->name); - if (type != DBUS_TYPE_STRING) + if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE) return -EINVAL; property = g_try_new0(struct connman_property, 1); @@ -686,11 +931,146 @@ int connman_element_add_static_property(struct connman_element *element, case DBUS_TYPE_STRING: property->value = g_strdup(*((const char **) value)); break; + case DBUS_TYPE_BYTE: + property->value = g_try_malloc(1); + if (property->value != NULL) + memcpy(property->value, value, 1); + break; + } + + __connman_element_lock(element); + element->properties = g_slist_append(element->properties, property); + __connman_element_unlock(element); + + return 0; +} + +static void emit_property_changed(DBusConnection *conn, + struct connman_element *element, + const char *name, int type, const void *data) +{ + DBusMessage *signal; + DBusMessageIter entry, value; + const char *iface, *sig; + + DBG("conn %p", conn); + + switch (element->type) { + case CONNMAN_ELEMENT_TYPE_CONNECTION: + iface = CONNMAN_CONNECTION_INTERFACE; + break; + default: + return; + } + + signal = dbus_message_new_signal(element->path, + iface, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name); + + switch (type) { + case DBUS_TYPE_STRING: + sig = DBUS_TYPE_STRING_AS_STRING; + break; + case DBUS_TYPE_BYTE: + sig = DBUS_TYPE_BYTE_AS_STRING; + break; + default: + sig = DBUS_TYPE_VARIANT_AS_STRING; + break; + } + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + sig, &value); + dbus_message_iter_append_basic(&value, type, data); + dbus_message_iter_close_container(&entry, &value); + + g_dbus_send_message(conn, signal); +} + +int connman_element_set_static_property(struct connman_element *element, + const char *name, int type, const void *value) +{ + GSList *list; + + DBG("element %p name %s", element, element->name); + + if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE) + return -EINVAL; + + __connman_element_lock(element); + + for (list = element->properties; list; list = list->next) { + struct connman_property *property = list->data; + + if (g_str_equal(property->name, name) == FALSE) + continue; + + if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) + continue; + + property->type = type; + g_free(property->value); + + switch (type) { + case DBUS_TYPE_STRING: + property->value = g_strdup(*((const char **) value)); + break; + case DBUS_TYPE_BYTE: + property->value = g_try_malloc(1); + if (property->value != NULL) + memcpy(property->value, value, 1); + break; + } + } + + __connman_element_unlock(element); + + emit_property_changed(connection, element, name, type, value); + + return 0; +} + +int connman_element_add_static_array_property(struct connman_element *element, + const char *name, int type, const void *value, int len) +{ + struct connman_property *property; + + DBG("element %p name %s", element, element->name); + + if (type != DBUS_TYPE_BYTE) + return -EINVAL; + + property = g_try_new0(struct connman_property, 1); + if (property == NULL) + return -ENOMEM; + + property->flags = CONNMAN_PROPERTY_FLAG_STATIC; + property->id = CONNMAN_PROPERTY_ID_INVALID; + property->name = g_strdup(name); + property->type = DBUS_TYPE_ARRAY; + property->subtype = type; + + DBG("name %s type %d value %p", name, type, value); + + switch (type) { + case DBUS_TYPE_BYTE: + property->value = g_try_malloc(len); + if (property->value != NULL) { + memcpy(property->value, + *((const unsigned char **) value), len); + property->size = len; + } + break; } - connman_element_lock(element); + __connman_element_lock(element); element->properties = g_slist_append(element->properties, property); - connman_element_unlock(element); + __connman_element_unlock(element); return 0; } @@ -743,7 +1123,7 @@ static struct connman_property *create_property(struct connman_element *element, DBG("element %p name %s", element, element->name); - connman_element_lock(element); + __connman_element_lock(element); for (list = element->properties; list; list = list->next) { property = list->data; @@ -770,7 +1150,7 @@ static struct connman_property *create_property(struct connman_element *element, element->properties = g_slist_append(element->properties, property); unlock: - connman_element_unlock(element); + __connman_element_unlock(element); return property; } @@ -856,38 +1236,51 @@ int connman_element_set_property(struct connman_element *element, { switch (id) { case CONNMAN_PROPERTY_ID_IPV4_ADDRESS: - connman_element_lock(element); + __connman_element_lock(element); g_free(element->ipv4.address); element->ipv4.address = g_strdup(*((const char **) value)); - connman_element_unlock(element); + __connman_element_unlock(element); break; case CONNMAN_PROPERTY_ID_IPV4_NETMASK: - connman_element_lock(element); + __connman_element_lock(element); g_free(element->ipv4.netmask); element->ipv4.netmask = g_strdup(*((const char **) value)); - connman_element_unlock(element); + __connman_element_unlock(element); break; case CONNMAN_PROPERTY_ID_IPV4_GATEWAY: - connman_element_lock(element); + __connman_element_lock(element); g_free(element->ipv4.gateway); element->ipv4.gateway = g_strdup(*((const char **) value)); - connman_element_unlock(element); + __connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_ID_IPV4_BROADCAST: + __connman_element_lock(element); + g_free(element->ipv4.broadcast); + element->ipv4.broadcast = g_strdup(*((const char **) value)); + __connman_element_unlock(element); break; case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER: - connman_element_lock(element); + __connman_element_lock(element); g_free(element->ipv4.nameserver); element->ipv4.nameserver = g_strdup(*((const char **) value)); - connman_element_unlock(element); + __connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_ID_WIFI_SECURITY: + __connman_element_lock(element); + g_free(element->wifi.security); + element->wifi.security = g_strdup(*((const char **) value)); + __connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE: + __connman_element_lock(element); + g_free(element->wifi.passphrase); + element->wifi.passphrase = g_strdup(*((const char **) value)); + __connman_element_unlock(element); break; default: return -EINVAL; } - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementUpdated", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); - return 0; } @@ -902,33 +1295,57 @@ int connman_element_get_value(struct connman_element *element, if (element->ipv4.address == NULL) return connman_element_get_value(element->parent, id, value); - connman_element_lock(element); + __connman_element_lock(element); *((char **) value) = element->ipv4.address; - connman_element_unlock(element); + __connman_element_unlock(element); break; case CONNMAN_PROPERTY_ID_IPV4_NETMASK: if (element->ipv4.netmask == NULL) return connman_element_get_value(element->parent, id, value); - connman_element_lock(element); + __connman_element_lock(element); *((char **) value) = element->ipv4.netmask; - connman_element_unlock(element); + __connman_element_unlock(element); break; case CONNMAN_PROPERTY_ID_IPV4_GATEWAY: if (element->ipv4.gateway == NULL) return connman_element_get_value(element->parent, id, value); - connman_element_lock(element); + __connman_element_lock(element); *((char **) value) = element->ipv4.gateway; - connman_element_unlock(element); + __connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_ID_IPV4_BROADCAST: + if (element->ipv4.broadcast == NULL) + return connman_element_get_value(element->parent, + id, value); + __connman_element_lock(element); + *((char **) value) = element->ipv4.broadcast; + __connman_element_unlock(element); break; case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER: if (element->ipv4.nameserver == NULL) return connman_element_get_value(element->parent, id, value); - connman_element_lock(element); + __connman_element_lock(element); *((char **) value) = element->ipv4.nameserver; - connman_element_unlock(element); + __connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_ID_WIFI_SECURITY: + if (element->wifi.security == NULL) + return connman_element_get_value(element->parent, + id, value); + __connman_element_lock(element); + *((char **) value) = element->wifi.security; + __connman_element_unlock(element); + break; + case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE: + if (element->wifi.passphrase == NULL) + return connman_element_get_value(element->parent, + id, value); + __connman_element_lock(element); + *((char **) value) = element->wifi.passphrase; + __connman_element_unlock(element); break; default: return -EINVAL; @@ -937,114 +1354,215 @@ int connman_element_get_value(struct connman_element *element, return 0; } -/** - * connman_element_register: - * @element: the element to register - * @parent: the parent to register the element with - * - * Register an element with the core. It will be register under the given - * parent of if %NULL is provided under the root element. - * - * Returns: %0 on success - */ -int connman_element_register(struct connman_element *element, - struct connman_element *parent) +gboolean connman_element_get_static_property(struct connman_element *element, + const char *name, void *value) { - DBG("element %p name %s parent %p", element, element->name, parent); + GSList *list; + gboolean found = FALSE; - if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) { - if (g_pattern_match_simple(device_filter, - element->name) == FALSE) { - DBG("ignoring %s device", element->name); - return -EPERM; + DBG("element %p name %s", element, element->name); + + __connman_element_lock(element); + + for (list = element->properties; list; list = list->next) { + struct connman_property *property = list->data; + + if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) + continue; + + if (g_str_equal(property->name, name) == TRUE) { + switch (property->type) { + case DBUS_TYPE_STRING: + *((char **) value) = property->value; + found = TRUE; + break; + } + break; } } - if (connman_element_ref(element) == NULL) - return -EINVAL; + __connman_element_unlock(element); - connman_element_lock(element); + return found; +} - __connman_element_load(element); +gboolean connman_element_get_static_array_property(struct connman_element *element, + const char *name, void *value, int *len) +{ + GSList *list; + gboolean found = FALSE; - if (element->name == NULL) { - element->name = g_strdup(type2string(element->type)); - if (element->name == NULL) { - connman_element_unlock(element); - return -EINVAL; + DBG("element %p name %s", element, element->name); + + __connman_element_lock(element); + + for (list = element->properties; list; list = list->next) { + struct connman_property *property = list->data; + + if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) + continue; + + if (g_str_equal(property->name, name) == TRUE) { + *((char **) value) = property->value; + *len = property->size; + found = TRUE; + break; } } - element->parent = parent; + __connman_element_unlock(element); - connman_element_unlock(element); + return found; +} - if (thread_register != NULL) - g_thread_pool_push(thread_register, element, NULL); +gboolean connman_element_match_static_property(struct connman_element *element, + const char *name, const void *value) +{ + GSList *list; + gboolean result = FALSE; - return 0; + DBG("element %p name %s", element, element->name); + + __connman_element_lock(element); + + for (list = element->properties; list; list = list->next) { + struct connman_property *property = list->data; + + if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) + continue; + + if (g_str_equal(property->name, name) == FALSE) + continue; + + if (property->type == DBUS_TYPE_STRING) + result = g_str_equal(property->value, + *((const char **) value)); + + if (result == TRUE) + break; + } + + __connman_element_unlock(element); + + return result; } -void connman_element_unregister(struct connman_element *element) +static void append_connections(DBusMessageIter *entry) { - DBG("element %p name %s", element, element->name); + DBusMessageIter value, iter; + const char *key = "Connections"; + + 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); - if (thread_unregister != NULL) - g_thread_pool_push(thread_unregister, element, NULL); + dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); + __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter); + dbus_message_iter_close_container(&value, &iter); + + dbus_message_iter_close_container(entry, &value); } -void connman_element_unregister_children(struct connman_element *element) +static void emit_connections_signal(DBusConnection *conn) { - DBG("element %p name %s", element, element->name); + DBusMessage *signal; + DBusMessageIter entry; - if (thread_unregister_children != NULL) - g_thread_pool_push(thread_unregister_children, element, NULL); + DBG("conn %p", conn); + + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + + append_connections(&entry); + + g_dbus_send_message(conn, signal); } -static gboolean update_element(GNode *node, gpointer user_data) +static void append_state(DBusMessageIter *entry, const char *state) { - struct connman_element *element = node->data; + DBusMessageIter value; + const char *key = "State"; - DBG("element %p name %s", element, element->name); + dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); - if (element->driver && element->driver->update) - element->driver->update(element); + dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_STRING_AS_STRING, &value); + dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state); + dbus_message_iter_close_container(entry, &value); +} - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementUpdated", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); +static void emit_state_change(DBusConnection *conn, const char *state) +{ + DBusMessage *signal; + DBusMessageIter entry; - return FALSE; + DBG("conn %p", conn); + + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + + append_state(&entry, state); + + g_dbus_send_message(conn, signal); } -void connman_element_update(struct connman_element *element) +static void set_signal_strength(struct connman_element *connection) { - GNode *node; + struct connman_element *element = connection; + + while (element != NULL) { + if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) { + connection->strength = element->strength; + break; + } + + element = element->parent; + } +} + +static void probe_element(struct connman_element *element) +{ + GSList *list; DBG("element %p name %s", element, element->name); - g_static_rw_lock_reader_lock(&element_lock); + for (list = driver_list; list; list = list->next) { + struct connman_driver *driver = list->data; - node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); + if (match_driver(element, driver) == FALSE) + continue; - if (node != NULL) - g_node_traverse(node, G_PRE_ORDER, - G_TRAVERSE_ALL, -1, update_element, NULL); + DBG("driver %p name %s", driver, driver->name); + + if (driver->probe(element) == 0) { + __connman_element_lock(element); + element->driver = driver; + __connman_element_unlock(element); - g_static_rw_lock_reader_unlock(&element_lock); + enable_element(element); + break; + } + } } static void register_element(gpointer data, gpointer user_data) { struct connman_element *element = data; const gchar *basepath; - GSList *list; GNode *node; - g_static_rw_lock_writer_lock(&element_lock); - - connman_element_lock(element); + __connman_element_lock(element); if (element->parent) { node = g_node_find(element_root, G_PRE_ORDER, @@ -1064,46 +1582,81 @@ static void register_element(gpointer data, gpointer user_data) set_reference_properties(element); - connman_element_unlock(element); + __connman_element_unlock(element); DBG("element %p path %s", element, element->path); g_node_append_data(node, element); - if (g_dbus_register_interface(connection, element->path, - CONNMAN_ELEMENT_INTERFACE, - element_methods, element_signals, + if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) { + if (g_dbus_register_interface(connection, element->path, + CONNMAN_CONNECTION_INTERFACE, + connection_methods, element_signals, NULL, element, NULL) == FALSE) - connman_error("Failed to register %s", element->path); + connman_error("Failed to register %s connection", + element->path); + else { + set_signal_strength(element); + emit_connections_signal(connection); + emit_state_change(connection, "online"); + } + } - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementAdded", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); + emit_element_signal(connection, "ElementAdded", element); - g_static_rw_lock_writer_unlock(&element_lock); + if (started == FALSE) + return; - __connman_element_store(element); + probe_element(element); +} - g_static_rw_lock_writer_lock(&element_lock); +/** + * connman_element_register: + * @element: the element to register + * @parent: the parent to register the element with + * + * Register an element with the core. It will be register under the given + * parent of if %NULL is provided under the root element. + * + * Returns: %0 on success + */ +int connman_element_register(struct connman_element *element, + struct connman_element *parent) +{ + DBG("element %p name %s parent %p", element, element->name, parent); - for (list = driver_list; list; list = list->next) { - struct connman_driver *driver = list->data; + if (element->devname == NULL) + element->devname = g_strdup(element->name); - if (match_driver(element, driver) == FALSE) - continue; + if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) { + if (g_pattern_match_simple(device_filter, + element->devname) == FALSE) { + DBG("ignoring %s [%s] device", element->name, + element->devname); + return -EPERM; + } + } - DBG("driver %p name %s", driver, driver->name); + if (connman_element_ref(element) == NULL) + return -EINVAL; - if (driver->probe(element) == 0) { - connman_element_lock(element); - element->driver = driver; - connman_element_unlock(element); - break; + __connman_element_lock(element); + + if (element->name == NULL) { + element->name = g_strdup(type2string(element->type)); + if (element->name == NULL) { + __connman_element_unlock(element); + return -EINVAL; } } - g_static_rw_lock_writer_unlock(&element_lock); + element->parent = parent; + + __connman_element_unlock(element); + + register_element(element, NULL); + + return 0; } static gboolean remove_element(GNode *node, gpointer user_data) @@ -1116,67 +1669,114 @@ static gboolean remove_element(GNode *node, gpointer user_data) if (element == root) return FALSE; + if (node != NULL) + g_node_unlink(node); + if (element->driver) { + disable_element(element); + if (element->driver->remove) element->driver->remove(element); - connman_element_lock(element); + __connman_element_lock(element); element->driver = NULL; - connman_element_unlock(element); + __connman_element_unlock(element); } - if (node != NULL) { - g_node_unlink(node); + if (node != NULL) g_node_destroy(node); - } - g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH, - CONNMAN_MANAGER_INTERFACE, "ElementRemoved", - DBUS_TYPE_OBJECT_PATH, &element->path, - DBUS_TYPE_INVALID); + if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) { + if (__connman_element_count(NULL, + CONNMAN_ELEMENT_TYPE_CONNECTION) == 0) + emit_state_change(connection, "offline"); + emit_connections_signal(connection); + + g_dbus_unregister_interface(connection, element->path, + CONNMAN_CONNECTION_INTERFACE); + } - g_dbus_unregister_interface(connection, element->path, - CONNMAN_ELEMENT_INTERFACE); + emit_element_signal(connection, "ElementRemoved", element); connman_element_unref(element); return FALSE; } -static void unregister_element(gpointer data, gpointer user_data) +void connman_element_unregister(struct connman_element *element) { - struct connman_element *element = data; GNode *node; DBG("element %p name %s", element, element->name); - g_static_rw_lock_writer_lock(&element_lock); - node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); if (node != NULL) g_node_traverse(node, G_POST_ORDER, G_TRAVERSE_ALL, -1, remove_element, NULL); - - g_static_rw_lock_writer_unlock(&element_lock); } -static void unregister_children(gpointer data, gpointer user_data) +void connman_element_unregister_children(struct connman_element *element) { - struct connman_element *element = data; GNode *node; DBG("element %p name %s", element, element->name); - g_static_rw_lock_writer_lock(&element_lock); - node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); if (node != NULL) g_node_traverse(node, G_POST_ORDER, G_TRAVERSE_ALL, -1, remove_element, element); +} + +static gboolean update_element(GNode *node, gpointer user_data) +{ + struct connman_element *element = node->data; + struct connman_element *root = user_data; + + DBG("element %p name %s", element, element->name); - g_static_rw_lock_writer_unlock(&element_lock); + if (element->driver && element->driver->update) + element->driver->update(element); + + if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION && + root->type == CONNMAN_ELEMENT_TYPE_NETWORK) { + if (element->strength != root->strength) { + element->strength = root->strength; + emit_property_changed(connection, element, "Strength", + DBUS_TYPE_BYTE, &element->strength); + } + } + + emit_element_signal(connection, "ElementUpdated", element); + + return FALSE; +} + +void connman_element_update(struct connman_element *element) +{ + GNode *node; + + DBG("element %p name %s", element, element->name); + + node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element); + + if (node != NULL) + g_node_traverse(node, G_PRE_ORDER, + G_TRAVERSE_ALL, -1, update_element, element); +} + +int connman_element_set_enabled(struct connman_element *element, + gboolean enabled) +{ + if (element->enabled == enabled) + return 0; + + element->enabled = enabled; + + emit_enabled_signal(connection, element); + + return 0; } int __connman_element_init(DBusConnection *conn, const char *device) @@ -1191,8 +1791,6 @@ int __connman_element_init(DBusConnection *conn, const char *device) device_filter = g_strdup(device); - g_static_rw_lock_writer_lock(&element_lock); - element = connman_element_create("root"); element->path = g_strdup("/"); @@ -1202,18 +1800,49 @@ int __connman_element_init(DBusConnection *conn, const char *device) element_root = g_node_new(element); - g_static_rw_lock_writer_unlock(&element_lock); - - thread_register = g_thread_pool_new(register_element, - NULL, 1, FALSE, NULL); - thread_unregister = g_thread_pool_new(unregister_element, - NULL, 1, FALSE, NULL); - thread_unregister_children = g_thread_pool_new(unregister_children, - NULL, 1, FALSE, NULL); + __connman_device_init(); + __connman_network_init(); + __connman_connection_init(); return 0; } +static gboolean probe_node(GNode *node, gpointer data) +{ + struct connman_element *element = node->data; + + DBG("element %p name %s", element, element->name); + + if (element->type == CONNMAN_ELEMENT_TYPE_ROOT) + return FALSE; + + if (element->driver) + return FALSE; + + probe_element(element); + + return FALSE; +} + +void __connman_element_start(void) +{ + DBG(""); + + g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + probe_node, NULL); + + started = TRUE; + + __connman_detect_init(); +} + +void __connman_element_stop(void) +{ + DBG(""); + + __connman_detect_cleanup(); +} + static gboolean free_driver(GNode *node, gpointer data) { struct connman_element *element = node->data; @@ -1221,12 +1850,14 @@ static gboolean free_driver(GNode *node, gpointer data) DBG("element %p name %s", element, element->name); if (element->driver) { + disable_element(element); + if (element->driver->remove) element->driver->remove(element); - connman_element_lock(element); + __connman_element_lock(element); element->driver = NULL; - connman_element_unlock(element); + __connman_element_unlock(element); } return FALSE; @@ -1239,7 +1870,7 @@ static gboolean free_node(GNode *node, gpointer data) DBG("element %p name %s", element, element->name); if (g_node_depth(node) > 1) - g_thread_pool_push(thread_unregister, element, NULL); + connman_element_unregister(element); return FALSE; } @@ -1248,29 +1879,18 @@ void __connman_element_cleanup(void) { DBG(""); - g_thread_pool_free(thread_register, TRUE, TRUE); - thread_register = NULL; + __connman_connection_cleanup(); + __connman_network_cleanup(); + __connman_device_cleanup(); - g_static_rw_lock_writer_lock(&element_lock); g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, free_driver, NULL); - g_static_rw_lock_writer_unlock(&element_lock); - g_static_rw_lock_writer_lock(&element_lock); g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1, free_node, NULL); - g_static_rw_lock_writer_unlock(&element_lock); - - g_thread_pool_free(thread_unregister, FALSE, TRUE); - thread_unregister = NULL; - - g_thread_pool_free(thread_unregister_children, FALSE, TRUE); - thread_unregister_children = NULL; - g_static_rw_lock_writer_lock(&element_lock); g_node_destroy(element_root); element_root = NULL; - g_static_rw_lock_writer_unlock(&element_lock); g_free(device_filter);