+ if (g_str_equal(name, "Powered") == TRUE) {
+ dbus_bool_t powered;
+
+ dbus_message_iter_get_basic(&value, &powered);
+
+ if (powered == TRUE)
+ do_enable(conn, msg, data);
+ else
+ do_disable(conn, msg, data);
+ } else
+ set_common_property(element, name, &value);
+
+ __connman_element_store(element);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static int parse_network_dict(DBusMessageIter *iter, const char **ssid,
+ const char **security, const char **passphrase)
+{
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(iter, &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:
+ if (g_str_equal(key, "WiFi.SSID") == TRUE)
+ dbus_message_iter_get_basic(&value, ssid);
+ else if (g_str_equal(key, "WiFi.Security") == TRUE)
+ dbus_message_iter_get_basic(&value, security);
+ else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
+ dbus_message_iter_get_basic(&value, passphrase);
+ break;
+ }
+
+ dbus_message_iter_next(iter);
+ }
+
+ return 0;
+}
+
+static DBusMessage *device_create_network(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_element *element = data;
+ struct connman_element *network;
+ DBusMessageIter iter, array;
+ const char *ssid = NULL, *security = NULL, *passphrase = NULL;
+
+ DBG("conn %p", conn);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_recurse(&iter, &array);
+ parse_network_dict(&array, &ssid, &security, &passphrase);
+ if (ssid == NULL)
+ return __connman_error_invalid_arguments(msg);
+
+ DBG("ssid %s security %s passphrase %s", ssid, security, passphrase);
+
+ network = connman_element_create(ssid);
+
+ network->type = CONNMAN_ELEMENT_TYPE_NETWORK;
+ network->index = element->index;
+
+ network->remember = TRUE;
+
+ connman_element_add_static_property(network, "Name",
+ DBUS_TYPE_STRING, &ssid);
+
+ connman_element_add_static_array_property(element, "WiFi.SSID",
+ DBUS_TYPE_BYTE, &ssid, strlen(ssid));
+
+ network->wifi.security = g_strdup(security);
+ network->wifi.passphrase = g_strdup(passphrase);
+
+ connman_element_register(network, element);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &network->path,
+ DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *device_remove_network(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *network_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);
+
+ 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);
+
+ str = __connman_element_policy2string(element->policy);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Policy",
+ DBUS_TYPE_STRING, &str);
+
+ connman_dbus_dict_append_variant(&dict, "Available",
+ DBUS_TYPE_BOOLEAN, &element->available);
+
+ connman_dbus_dict_append_variant(&dict, "Connected",
+ DBUS_TYPE_BOOLEAN, &element->enabled);
+
+ connman_dbus_dict_append_variant(&dict, "Remember",
+ DBUS_TYPE_BOOLEAN, &element->remember);
+
+ add_common_properties(element, &dict);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *network_set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_element *element = data;
+ DBusMessageIter iter;
+ DBusMessageIter value;
+ const char *name;
+
+ 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, "Remember") == TRUE) {
+ dbus_message_iter_get_basic(&value, &element->remember);
+ } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
+ const char *str;
+
+ dbus_message_iter_get_basic(&value, &str);
+ g_free(element->wifi.passphrase);
+ element->wifi.passphrase = g_strdup(str);
+ } else
+ set_common_property(element, name, &value);
+
+ __connman_element_store(element);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *get_connection_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_element *element = data;
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+
+ 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);
+
+ add_common_properties(element, &dict);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+#if 0
+static DBusMessage *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);
+
+ 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) {
+ connman_dbus_dict_append_variant(&dict, "Parent",
+ DBUS_TYPE_OBJECT_PATH, &element->parent->path);
+ }
+
+ str = type2string(element->type);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = subtype2string(element->subtype);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Subtype",
+ DBUS_TYPE_STRING, &str);
+
+ connman_dbus_dict_append_variant(&dict, "Enabled",
+ DBUS_TYPE_BOOLEAN, &element->enabled);
+
+ add_common_properties(element, &dict);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_element *element = data;
+ DBusMessageIter iter;
+ DBusMessageIter value;
+ const char *name;
+
+ 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);
+
+ set_common_property(element, name, &value);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *clear_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_element *element = data;
+ const char *name;
+ GSList *list;
+
+ 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 (__connman_security_check_privileges(msg) < 0)
+ return __connman_error_permission_denied(msg);
+
+ __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;
+
+ if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)
+ continue;
+
+ property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE;
+
+ if (property->type == DBUS_TYPE_STRING)
+ g_free(property->value);
+
+ property->value = NULL;
+ }
+
+ __connman_element_unlock(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 },
+ { },
+};
+#endif
+
+static GDBusSignalTable element_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },
+};
+
+static GDBusMethodTable device_methods[] = {
+ { "GetProperties", "", "a{sv}", device_get_properties },
+ { "SetProperty", "sv", "", device_set_property },
+ { "CreateNetwork", "a{sv}", "o", device_create_network },
+ { "RemoveNetwork", "o", "", device_remove_network },
+ { "ProposeScan", "", "", do_update },
+ { },
+};
+
+static GDBusMethodTable network_methods[] = {
+ { "GetProperties", "", "a{sv}", network_get_properties },
+ { "SetProperty", "sv", "", network_set_property },
+ { "Connect", "", "", do_enable },
+ { "Disconnect", "", "", do_disable },
+ { },
+};
+
+static GDBusMethodTable connection_methods[] = {
+ { "GetProperties", "", "a{sv}", get_connection_properties },
+ { },
+};
+
+struct append_filter {
+ enum connman_element_type type;
+ DBusMessageIter *iter;
+};
+
+static gboolean append_path(GNode *node, gpointer user_data)
+{
+ struct connman_element *element = node->data;
+ struct append_filter *filter = user_data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
+ filter->type != element->type)
+ return FALSE;
+
+ if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
+ element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
+ return FALSE;
+
+ dbus_message_iter_append_basic(filter->iter,
+ DBUS_TYPE_OBJECT_PATH, &element->path);
+
+ return FALSE;
+}
+
+void __connman_element_list(struct connman_element *element,
+ enum connman_element_type type,
+ DBusMessageIter *iter)
+{
+ struct append_filter filter = { type, iter };
+ 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,
+ 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)
+{
+ const struct connman_driver *driver1 = a;
+ const struct connman_driver *driver2 = b;
+
+ return driver2->priority - driver1->priority;
+}
+
+static gboolean match_driver(struct connman_element *element,
+ struct connman_driver *driver)
+{
+ if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
+ return FALSE;
+
+ if (element->type != driver->type &&
+ driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
+ return FALSE;
+
+ if (element->subtype == driver->subtype ||
+ driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
+ return TRUE;
+
+ 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;
+ struct connman_driver *driver = data;
+
+ DBG("element %p name %s", element, element->name);
+
+ if (!element->driver && match_driver(element, driver) == TRUE) {
+ if (driver->probe(element) < 0)
+ return FALSE;
+
+ __connman_element_lock(element);
+ element->driver = driver;
+ __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,