5 * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 static DBusConnection *connection;
35 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
36 static GNode *element_root = NULL;
38 static GSList *driver_list = NULL;
40 static GThreadPool *thread_register = NULL;
41 static GThreadPool *thread_unregister = NULL;
42 static GThreadPool *thread_unregister_children = NULL;
44 static gchar *device_filter = NULL;
46 static const char *type2string(enum connman_element_type type)
49 case CONNMAN_ELEMENT_TYPE_UNKNOWN:
51 case CONNMAN_ELEMENT_TYPE_ROOT:
53 case CONNMAN_ELEMENT_TYPE_DEVICE:
55 case CONNMAN_ELEMENT_TYPE_NETWORK:
57 case CONNMAN_ELEMENT_TYPE_IPV4:
59 case CONNMAN_ELEMENT_TYPE_IPV6:
61 case CONNMAN_ELEMENT_TYPE_DHCP:
63 case CONNMAN_ELEMENT_TYPE_BOOTP:
65 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
67 case CONNMAN_ELEMENT_TYPE_RESOLVER:
69 case CONNMAN_ELEMENT_TYPE_INTERNET:
76 static const char *subtype2string(enum connman_element_subtype type)
79 case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
81 case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
83 case CONNMAN_ELEMENT_SUBTYPE_WIFI:
85 case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
87 case CONNMAN_ELEMENT_SUBTYPE_MODEM:
89 case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
96 static void append_entry(DBusMessageIter *dict,
97 const char *key, int type, void *val)
99 DBusMessageIter entry, value;
100 const char *signature;
102 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
105 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
108 case DBUS_TYPE_BOOLEAN:
109 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
111 case DBUS_TYPE_STRING:
112 signature = DBUS_TYPE_STRING_AS_STRING;
114 case DBUS_TYPE_UINT16:
115 signature = DBUS_TYPE_UINT16_AS_STRING;
117 case DBUS_TYPE_UINT32:
118 signature = DBUS_TYPE_UINT32_AS_STRING;
120 case DBUS_TYPE_OBJECT_PATH:
121 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
124 signature = DBUS_TYPE_VARIANT_AS_STRING;
128 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
130 dbus_message_iter_append_basic(&value, type, val);
131 dbus_message_iter_close_container(&entry, &value);
133 dbus_message_iter_close_container(dict, &entry);
136 static void append_property(DBusMessageIter *dict,
137 struct connman_property *property)
139 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
140 append_entry(dict, property->name, property->type,
146 static DBusMessage *get_properties(DBusConnection *conn,
147 DBusMessage *msg, void *data)
149 struct connman_element *element = data;
152 DBusMessageIter array, dict;
155 DBG("conn %p", conn);
157 reply = dbus_message_new_method_return(msg);
161 dbus_message_iter_init_append(reply, &array);
163 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
164 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
165 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
166 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
168 if (element->parent != NULL)
169 append_entry(&dict, "Parent",
170 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
172 str = type2string(element->type);
174 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
175 str = subtype2string(element->subtype);
177 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
179 append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &element->enabled);
181 if (element->priority > 0)
182 append_entry(&dict, "Priority",
183 DBUS_TYPE_UINT16, &element->priority);
185 if (element->network.identifier != NULL)
186 append_entry(&dict, "Identifier",
187 DBUS_TYPE_STRING, &element->network.identifier);
189 if (element->ipv4.address != NULL)
190 append_entry(&dict, "IPv4.Address",
191 DBUS_TYPE_STRING, &element->ipv4.address);
192 if (element->ipv4.netmask != NULL)
193 append_entry(&dict, "IPv4.Netmask",
194 DBUS_TYPE_STRING, &element->ipv4.netmask);
195 if (element->ipv4.gateway != NULL)
196 append_entry(&dict, "IPv4.Gateway",
197 DBUS_TYPE_STRING, &element->ipv4.gateway);
199 for (list = element->properties; list; list = list->next) {
200 struct connman_property *property = list->data;
202 append_property(&dict, property);
205 dbus_message_iter_close_container(&array, &dict);
210 static DBusMessage *set_property(DBusConnection *conn,
211 DBusMessage *msg, void *data)
213 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
216 static DBusMessage *do_update(DBusConnection *conn,
217 DBusMessage *msg, void *data)
219 struct connman_element *element = data;
221 DBG("conn %p", conn);
223 if (element->driver == NULL)
224 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
226 if (element->driver->update) {
227 DBG("Calling update callback");
228 element->driver->update(element);
231 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
234 static DBusMessage *do_enable(DBusConnection *conn,
235 DBusMessage *msg, void *data)
237 struct connman_element *element = data;
239 DBG("conn %p", conn);
241 if (element->driver == NULL)
242 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
244 if (element->driver->enable) {
245 DBG("Calling enable callback");
246 element->driver->enable(element);
249 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
252 static DBusMessage *do_disable(DBusConnection *conn,
253 DBusMessage *msg, void *data)
255 struct connman_element *element = data;
257 DBG("conn %p", conn);
259 if (element->driver == NULL)
260 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
262 if (element->driver->disable) {
263 DBG("Calling disable callback");
264 element->driver->disable(element);
267 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
270 static GDBusMethodTable element_methods[] = {
271 { "GetProperties", "", "a{sv}", get_properties },
272 { "SetProperty", "sv", "", set_property },
273 { "Update", "", "", do_update },
274 { "Enable", "", "", do_enable },
275 { "Disable", "", "", do_disable },
279 static GDBusSignalTable element_signals[] = {
280 { "PropertyChanged", "sv" },
284 struct append_filter {
285 enum connman_element_type type;
286 DBusMessageIter *iter;
289 static gboolean append_path(GNode *node, gpointer data)
291 struct connman_element *element = node->data;
292 struct append_filter *filter = data;
294 DBG("element %p name %s", element, element->name);
296 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
299 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
300 filter->type != element->type)
303 dbus_message_iter_append_basic(filter->iter,
304 DBUS_TYPE_OBJECT_PATH, &element->path);
309 void __connman_element_list(enum connman_element_type type,
310 DBusMessageIter *iter)
312 struct append_filter filter = { type, iter };
316 g_static_rw_lock_reader_lock(&element_lock);
317 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
318 append_path, &filter);
319 g_static_rw_lock_reader_unlock(&element_lock);
322 static gint compare_priority(gconstpointer a, gconstpointer b)
324 const struct connman_driver *driver1 = a;
325 const struct connman_driver *driver2 = b;
327 return driver2->priority - driver1->priority;
330 static gboolean match_driver(struct connman_element *element,
331 struct connman_driver *driver)
333 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
336 if (element->type != driver->type &&
337 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
340 if (element->subtype == driver->subtype ||
341 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
347 static gboolean probe_driver(GNode *node, gpointer data)
349 struct connman_element *element = node->data;
350 struct connman_driver *driver = data;
352 DBG("element %p name %s", element, element->name);
354 if (!element->driver && match_driver(element, driver) == TRUE) {
355 if (driver->probe(element) < 0)
358 connman_element_lock(element);
359 element->driver = driver;
360 connman_element_unlock(element);
366 int connman_driver_register(struct connman_driver *driver)
368 DBG("driver %p name %s", driver, driver->name);
370 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
376 g_static_rw_lock_writer_lock(&element_lock);
378 driver_list = g_slist_insert_sorted(driver_list, driver,
381 if (element_root != NULL)
382 g_node_traverse(element_root, G_PRE_ORDER,
383 G_TRAVERSE_ALL, -1, probe_driver, driver);
385 g_static_rw_lock_writer_unlock(&element_lock);
390 static gboolean remove_driver(GNode *node, gpointer data)
392 struct connman_element *element = node->data;
393 struct connman_driver *driver = data;
395 DBG("element %p name %s", element, element->name);
397 if (element->driver == driver) {
399 driver->remove(element);
401 connman_element_lock(element);
402 element->driver = NULL;
403 connman_element_unlock(element);
409 void connman_driver_unregister(struct connman_driver *driver)
411 DBG("driver %p name %s", driver, driver->name);
413 g_static_rw_lock_writer_lock(&element_lock);
415 driver_list = g_slist_remove(driver_list, driver);
417 if (element_root != NULL)
418 g_node_traverse(element_root, G_POST_ORDER,
419 G_TRAVERSE_ALL, -1, remove_driver, driver);
421 g_static_rw_lock_writer_unlock(&element_lock);
424 struct connman_element *connman_element_create(void)
426 struct connman_element *element;
428 element = g_new0(struct connman_element, 1);
430 DBG("element %p", element);
432 element->refcount = 1;
434 g_static_mutex_init(&element->mutex);
436 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
437 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
438 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
440 element->enabled = FALSE;
442 element->netdev.index = -1;
447 struct connman_element *connman_element_ref(struct connman_element *element)
449 DBG("element %p name %s refcount %d", element, element->name,
450 g_atomic_int_get(&element->refcount) + 1);
452 g_atomic_int_inc(&element->refcount);
457 void connman_element_unref(struct connman_element *element)
459 DBG("element %p name %s refcount %d", element, element->name,
460 g_atomic_int_get(&element->refcount) - 1);
462 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
465 for (list = element->properties; list; list = list->next) {
466 struct connman_property *property = list->data;
467 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
468 property->type == DBUS_TYPE_STRING)
469 g_free(property->value);
473 g_slist_free(element->properties);
475 g_free(element->ipv4.address);
476 g_free(element->ipv4.netmask);
477 g_free(element->ipv4.gateway);
478 g_free(element->ipv4.network);
479 g_free(element->ipv4.broadcast);
480 g_free(element->ipv4.nameserver);
481 g_free(element->network.identifier);
482 g_free(element->netdev.name);
483 g_free(element->path);
484 g_free(element->name);
489 int connman_element_add_static_property(struct connman_element *element,
490 const char *name, int type, const void *value)
492 struct connman_property *property;
494 DBG("element %p name %s", element, element->name);
496 if (type != DBUS_TYPE_STRING)
499 property = g_try_new0(struct connman_property, 1);
500 if (property == NULL)
503 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
505 property->name = g_strdup(name);
506 property->type = type;
508 DBG("name %s type %d value %p", name, type, value);
511 case DBUS_TYPE_STRING:
512 property->value = g_strdup(*((const char **) value));
516 connman_element_lock(element);
517 element->properties = g_slist_append(element->properties, property);
518 connman_element_unlock(element);
523 int connman_element_set_property(struct connman_element *element,
524 enum connman_property_type type, const void *value)
527 case CONNMAN_PROPERTY_TYPE_INVALID:
529 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
530 connman_element_lock(element);
531 g_free(element->ipv4.address);
532 element->ipv4.address = g_strdup(*((const char **) value));
533 connman_element_unlock(element);
535 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
536 connman_element_lock(element);
537 g_free(element->ipv4.netmask);
538 element->ipv4.netmask = g_strdup(*((const char **) value));
539 connman_element_unlock(element);
541 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
542 connman_element_lock(element);
543 g_free(element->ipv4.gateway);
544 element->ipv4.gateway = g_strdup(*((const char **) value));
545 connman_element_unlock(element);
547 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
548 connman_element_lock(element);
549 g_free(element->ipv4.nameserver);
550 element->ipv4.nameserver = g_strdup(*((const char **) value));
551 connman_element_unlock(element);
555 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
556 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
557 DBUS_TYPE_OBJECT_PATH, &element->path,
563 int connman_element_get_value(struct connman_element *element,
564 enum connman_property_type type, void *value)
566 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
570 case CONNMAN_PROPERTY_TYPE_INVALID:
572 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
573 if (element->ipv4.address == NULL)
574 return connman_element_get_value(element->parent,
576 connman_element_lock(element);
577 *((char **) value) = element->ipv4.address;
578 connman_element_unlock(element);
580 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
581 if (element->ipv4.netmask == NULL)
582 return connman_element_get_value(element->parent,
584 connman_element_lock(element);
585 *((char **) value) = element->ipv4.netmask;
586 connman_element_unlock(element);
588 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
589 if (element->ipv4.gateway == NULL)
590 return connman_element_get_value(element->parent,
592 connman_element_lock(element);
593 *((char **) value) = element->ipv4.gateway;
594 connman_element_unlock(element);
596 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
597 if (element->ipv4.nameserver == NULL)
598 return connman_element_get_value(element->parent,
600 connman_element_lock(element);
601 *((char **) value) = element->ipv4.nameserver;
602 connman_element_unlock(element);
609 int connman_element_register(struct connman_element *element,
610 struct connman_element *parent)
612 DBG("element %p name %s parent %p", element, element->name, parent);
614 if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
615 if (g_str_equal(device_filter, element->netdev.name) == FALSE)
619 if (connman_element_ref(element) == NULL)
622 connman_element_lock(element);
624 __connman_element_load(element);
626 if (element->name == NULL) {
627 element->name = g_strdup(type2string(element->type));
628 if (element->name == NULL)
632 element->parent = parent;
634 connman_element_unlock(element);
636 if (thread_register != NULL)
637 g_thread_pool_push(thread_register, element, NULL);
642 void connman_element_unregister(struct connman_element *element)
644 DBG("element %p name %s", element, element->name);
646 if (thread_unregister != NULL)
647 g_thread_pool_push(thread_unregister, element, NULL);
650 void connman_element_unregister_children(struct connman_element *element)
652 DBG("element %p name %s", element, element->name);
654 if (thread_unregister_children != NULL)
655 g_thread_pool_push(thread_unregister_children, element, NULL);
658 static gboolean update_element(GNode *node, gpointer user_data)
660 struct connman_element *element = node->data;
662 DBG("element %p name %s", element, element->name);
664 if (element->driver && element->driver->update)
665 element->driver->update(element);
667 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
668 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
669 DBUS_TYPE_OBJECT_PATH, &element->path,
675 void connman_element_update(struct connman_element *element)
679 DBG("element %p name %s", element, element->name);
681 g_static_rw_lock_reader_lock(&element_lock);
683 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
686 g_node_traverse(node, G_PRE_ORDER,
687 G_TRAVERSE_ALL, -1, update_element, NULL);
689 g_static_rw_lock_reader_unlock(&element_lock);
692 static void register_element(gpointer data, gpointer user_data)
694 struct connman_element *element = data;
695 const gchar *basepath;
699 g_static_rw_lock_writer_lock(&element_lock);
701 connman_element_lock(element);
703 if (element->parent) {
704 node = g_node_find(element_root, G_PRE_ORDER,
705 G_TRAVERSE_ALL, element->parent);
706 basepath = element->parent->path;
708 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
709 element->subtype = element->parent->subtype;
715 element->path = g_strdup_printf("%s/%s", basepath, element->name);
717 connman_element_unlock(element);
719 DBG("element %p path %s", element, element->path);
721 g_node_append_data(node, element);
723 if (g_dbus_register_interface(connection, element->path,
724 CONNMAN_ELEMENT_INTERFACE,
725 element_methods, element_signals,
726 NULL, element, NULL) == FALSE)
727 connman_error("Failed to register %s", element->path);
729 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
730 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
731 DBUS_TYPE_OBJECT_PATH, &element->path,
734 g_static_rw_lock_writer_unlock(&element_lock);
736 __connman_element_store(element);
738 g_static_rw_lock_writer_lock(&element_lock);
740 for (list = driver_list; list; list = list->next) {
741 struct connman_driver *driver = list->data;
743 if (match_driver(element, driver) == FALSE)
746 DBG("driver %p name %s", driver, driver->name);
748 if (driver->probe(element) == 0) {
749 connman_element_lock(element);
750 element->driver = driver;
751 connman_element_unlock(element);
756 g_static_rw_lock_writer_unlock(&element_lock);
759 static gboolean remove_element(GNode *node, gpointer user_data)
761 struct connman_element *element = node->data;
762 struct connman_element *root = user_data;
764 DBG("element %p name %s", element, element->name);
769 if (element->driver) {
770 if (element->driver->remove)
771 element->driver->remove(element);
773 connman_element_lock(element);
774 element->driver = NULL;
775 connman_element_unlock(element);
780 g_node_destroy(node);
783 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
784 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
785 DBUS_TYPE_OBJECT_PATH, &element->path,
788 g_dbus_unregister_interface(connection, element->path,
789 CONNMAN_ELEMENT_INTERFACE);
791 connman_element_unref(element);
796 static void unregister_element(gpointer data, gpointer user_data)
798 struct connman_element *element = data;
801 DBG("element %p name %s", element, element->name);
803 g_static_rw_lock_writer_lock(&element_lock);
805 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
808 g_node_traverse(node, G_POST_ORDER,
809 G_TRAVERSE_ALL, -1, remove_element, NULL);
811 g_static_rw_lock_writer_unlock(&element_lock);
814 static void unregister_children(gpointer data, gpointer user_data)
816 struct connman_element *element = data;
819 DBG("element %p name %s", element, element->name);
821 g_static_rw_lock_writer_lock(&element_lock);
823 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
826 g_node_traverse(node, G_POST_ORDER,
827 G_TRAVERSE_ALL, -1, remove_element, element);
829 g_static_rw_lock_writer_unlock(&element_lock);
832 int __connman_element_init(DBusConnection *conn, const char *device)
834 struct connman_element *element;
836 DBG("conn %p", conn);
838 connection = dbus_connection_ref(conn);
839 if (connection == NULL)
842 device_filter = g_strdup(device);
844 g_static_rw_lock_writer_lock(&element_lock);
846 element = connman_element_create();
848 element->name = g_strdup("root");
849 element->path = g_strdup("/");
850 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
852 element_root = g_node_new(element);
854 g_static_rw_lock_writer_unlock(&element_lock);
856 thread_register = g_thread_pool_new(register_element,
857 NULL, 1, FALSE, NULL);
858 thread_unregister = g_thread_pool_new(unregister_element,
859 NULL, 1, FALSE, NULL);
860 thread_unregister_children = g_thread_pool_new(unregister_children,
861 NULL, 1, FALSE, NULL);
866 static gboolean free_driver(GNode *node, gpointer data)
868 struct connman_element *element = node->data;
870 DBG("element %p name %s", element, element->name);
872 if (element->driver) {
873 if (element->driver->remove)
874 element->driver->remove(element);
876 connman_element_lock(element);
877 element->driver = NULL;
878 connman_element_unlock(element);
884 static gboolean free_node(GNode *node, gpointer data)
886 struct connman_element *element = node->data;
888 DBG("element %p name %s", element, element->name);
890 if (g_node_depth(node) > 1)
891 g_thread_pool_push(thread_unregister, element, NULL);
896 void __connman_element_cleanup(void)
900 g_thread_pool_free(thread_register, TRUE, TRUE);
901 thread_register = NULL;
903 g_static_rw_lock_writer_lock(&element_lock);
904 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
906 g_static_rw_lock_writer_unlock(&element_lock);
908 g_static_rw_lock_writer_lock(&element_lock);
909 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
911 g_static_rw_lock_writer_unlock(&element_lock);
913 g_thread_pool_free(thread_unregister, FALSE, TRUE);
914 thread_unregister = NULL;
916 g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
917 thread_unregister_children = NULL;
919 g_static_rw_lock_writer_lock(&element_lock);
920 g_node_destroy(element_root);
922 g_static_rw_lock_writer_unlock(&element_lock);
924 g_free(device_filter);
926 dbus_connection_unref(connection);