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;
43 static const char *type2string(enum connman_element_type type)
46 case CONNMAN_ELEMENT_TYPE_UNKNOWN:
48 case CONNMAN_ELEMENT_TYPE_ROOT:
50 case CONNMAN_ELEMENT_TYPE_DEVICE:
52 case CONNMAN_ELEMENT_TYPE_NETWORK:
54 case CONNMAN_ELEMENT_TYPE_IPV4:
56 case CONNMAN_ELEMENT_TYPE_IPV6:
58 case CONNMAN_ELEMENT_TYPE_DHCP:
60 case CONNMAN_ELEMENT_TYPE_BOOTP:
62 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
64 case CONNMAN_ELEMENT_TYPE_RESOLVER:
66 case CONNMAN_ELEMENT_TYPE_INTERNET:
73 static const char *subtype2string(enum connman_element_subtype type)
76 case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
78 case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
80 case CONNMAN_ELEMENT_SUBTYPE_WIFI:
82 case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
84 case CONNMAN_ELEMENT_SUBTYPE_MODEM:
86 case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
93 static void append_entry(DBusMessageIter *dict,
94 const char *key, int type, void *val)
96 DBusMessageIter entry, value;
97 const char *signature;
99 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
102 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
105 case DBUS_TYPE_STRING:
106 signature = DBUS_TYPE_STRING_AS_STRING;
108 case DBUS_TYPE_UINT16:
109 signature = DBUS_TYPE_UINT16_AS_STRING;
111 case DBUS_TYPE_UINT32:
112 signature = DBUS_TYPE_UINT32_AS_STRING;
114 case DBUS_TYPE_OBJECT_PATH:
115 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
118 signature = DBUS_TYPE_VARIANT_AS_STRING;
122 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
124 dbus_message_iter_append_basic(&value, type, val);
125 dbus_message_iter_close_container(&entry, &value);
127 dbus_message_iter_close_container(dict, &entry);
130 static void append_property(DBusMessageIter *dict,
131 struct connman_property *property)
133 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
134 append_entry(dict, property->name, property->type,
140 static DBusMessage *get_properties(DBusConnection *conn,
141 DBusMessage *msg, void *data)
143 struct connman_element *element = data;
146 DBusMessageIter array, dict;
149 DBG("conn %p", conn);
151 reply = dbus_message_new_method_return(msg);
155 dbus_message_iter_init_append(reply, &array);
157 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
158 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
159 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
160 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
162 if (element->parent != NULL)
163 append_entry(&dict, "Parent",
164 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
166 str = type2string(element->type);
168 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
169 str = subtype2string(element->subtype);
171 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
173 if (element->priority > 0)
174 append_entry(&dict, "Priority",
175 DBUS_TYPE_UINT16, &element->priority);
177 if (element->network.identifier != NULL)
178 append_entry(&dict, "Identifier",
179 DBUS_TYPE_STRING, &element->network.identifier);
181 if (element->ipv4.address != NULL)
182 append_entry(&dict, "IPv4.Address",
183 DBUS_TYPE_STRING, &element->ipv4.address);
184 if (element->ipv4.netmask != NULL)
185 append_entry(&dict, "IPv4.Netmask",
186 DBUS_TYPE_STRING, &element->ipv4.netmask);
187 if (element->ipv4.gateway != NULL)
188 append_entry(&dict, "IPv4.Gateway",
189 DBUS_TYPE_STRING, &element->ipv4.gateway);
191 for (list = element->properties; list; list = list->next) {
192 struct connman_property *property = list->data;
194 append_property(&dict, property);
197 dbus_message_iter_close_container(&array, &dict);
202 static GDBusMethodTable element_methods[] = {
203 { "GetProperties", "", "a{sv}", get_properties },
207 struct append_filter {
208 enum connman_element_type type;
209 DBusMessageIter *iter;
212 static gboolean append_path(GNode *node, gpointer data)
214 struct connman_element *element = node->data;
215 struct append_filter *filter = data;
217 DBG("element %p name %s", element, element->name);
219 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
222 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
223 filter->type != element->type)
226 dbus_message_iter_append_basic(filter->iter,
227 DBUS_TYPE_OBJECT_PATH, &element->path);
232 void __connman_element_list(enum connman_element_type type,
233 DBusMessageIter *iter)
235 struct append_filter filter = { type, iter };
239 g_static_rw_lock_reader_lock(&element_lock);
240 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
241 append_path, &filter);
242 g_static_rw_lock_reader_unlock(&element_lock);
245 static gint compare_priority(gconstpointer a, gconstpointer b)
247 const struct connman_driver *driver1 = a;
248 const struct connman_driver *driver2 = b;
250 return driver2->priority - driver1->priority;
253 static gboolean match_driver(struct connman_element *element,
254 struct connman_driver *driver)
256 if (element->type != driver->type &&
257 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
260 if (element->subtype == driver->subtype ||
261 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
267 static gboolean probe_driver(GNode *node, gpointer data)
269 struct connman_element *element = node->data;
270 struct connman_driver *driver = data;
272 DBG("element %p name %s", element, element->name);
274 if (!element->driver && match_driver(element, driver) == TRUE) {
275 if (driver->probe(element) < 0)
278 connman_element_lock(element);
279 element->driver = driver;
280 connman_element_unlock(element);
286 int connman_driver_register(struct connman_driver *driver)
288 DBG("driver %p name %s", driver, driver->name);
290 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
296 g_static_rw_lock_writer_lock(&element_lock);
298 driver_list = g_slist_insert_sorted(driver_list, driver,
301 if (element_root != NULL)
302 g_node_traverse(element_root, G_PRE_ORDER,
303 G_TRAVERSE_ALL, -1, probe_driver, driver);
305 g_static_rw_lock_writer_unlock(&element_lock);
310 static gboolean remove_driver(GNode *node, gpointer data)
312 struct connman_element *element = node->data;
313 struct connman_driver *driver = data;
315 DBG("element %p name %s", element, element->name);
317 if (element->driver == driver) {
319 driver->remove(element);
321 connman_element_lock(element);
322 element->driver = NULL;
323 connman_element_unlock(element);
329 void connman_driver_unregister(struct connman_driver *driver)
331 DBG("driver %p name %s", driver, driver->name);
333 g_static_rw_lock_writer_lock(&element_lock);
335 driver_list = g_slist_remove(driver_list, driver);
337 if (element_root != NULL)
338 g_node_traverse(element_root, G_POST_ORDER,
339 G_TRAVERSE_ALL, -1, remove_driver, driver);
341 g_static_rw_lock_writer_unlock(&element_lock);
344 struct connman_element *connman_element_create(void)
346 struct connman_element *element;
348 element = g_new0(struct connman_element, 1);
350 DBG("element %p", element);
352 element->refcount = 1;
354 g_static_mutex_init(&element->mutex);
356 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
357 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
358 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
360 element->netdev.index = -1;
365 struct connman_element *connman_element_ref(struct connman_element *element)
367 DBG("element %p name %s refcount %d", element, element->name,
368 g_atomic_int_get(&element->refcount) + 1);
370 g_atomic_int_inc(&element->refcount);
375 void connman_element_unref(struct connman_element *element)
377 DBG("element %p name %s refcount %d", element, element->name,
378 g_atomic_int_get(&element->refcount) - 1);
380 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
383 for (list = element->properties; list; list = list->next) {
384 struct connman_property *property = list->data;
385 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
386 property->type == DBUS_TYPE_STRING)
387 g_free(property->value);
391 g_slist_free(element->properties);
393 g_free(element->ipv4.address);
394 g_free(element->ipv4.netmask);
395 g_free(element->ipv4.gateway);
396 g_free(element->ipv4.network);
397 g_free(element->ipv4.broadcast);
398 g_free(element->ipv4.nameserver);
399 g_free(element->network.identifier);
400 g_free(element->netdev.name);
401 g_free(element->path);
402 g_free(element->name);
407 int connman_element_add_static_property(struct connman_element *element,
408 const char *name, int type, const void *value)
410 struct connman_property *property;
412 DBG("element %p name %s", element, element->name);
414 if (type != DBUS_TYPE_STRING)
417 property = g_try_new0(struct connman_property, 1);
418 if (property == NULL)
421 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
423 property->name = g_strdup(name);
424 property->type = type;
426 DBG("name %s type %d value %p", name, type, value);
429 case DBUS_TYPE_STRING:
430 property->value = g_strdup(*((const char **) value));
434 connman_element_lock(element);
435 element->properties = g_slist_append(element->properties, property);
436 connman_element_unlock(element);
441 int connman_element_set_property(struct connman_element *element,
442 enum connman_property_type type, const void *value)
445 case CONNMAN_PROPERTY_TYPE_INVALID:
447 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
448 connman_element_lock(element);
449 g_free(element->ipv4.address);
450 element->ipv4.address = g_strdup(*((const char **) value));
451 connman_element_unlock(element);
453 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
454 connman_element_lock(element);
455 g_free(element->ipv4.netmask);
456 element->ipv4.netmask = g_strdup(*((const char **) value));
457 connman_element_unlock(element);
459 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
460 connman_element_lock(element);
461 g_free(element->ipv4.gateway);
462 element->ipv4.gateway = g_strdup(*((const char **) value));
463 connman_element_unlock(element);
465 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
466 connman_element_lock(element);
467 g_free(element->ipv4.nameserver);
468 element->ipv4.nameserver = g_strdup(*((const char **) value));
469 connman_element_unlock(element);
473 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
474 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
475 DBUS_TYPE_OBJECT_PATH, &element->path,
481 int connman_element_get_value(struct connman_element *element,
482 enum connman_property_type type, void *value)
484 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
488 case CONNMAN_PROPERTY_TYPE_INVALID:
490 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
491 if (element->ipv4.address == NULL)
492 return connman_element_get_value(element->parent,
494 connman_element_lock(element);
495 *((char **) value) = element->ipv4.address;
496 connman_element_unlock(element);
498 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
499 if (element->ipv4.netmask == NULL)
500 return connman_element_get_value(element->parent,
502 connman_element_lock(element);
503 *((char **) value) = element->ipv4.netmask;
504 connman_element_unlock(element);
506 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
507 if (element->ipv4.gateway == NULL)
508 return connman_element_get_value(element->parent,
510 connman_element_lock(element);
511 *((char **) value) = element->ipv4.gateway;
512 connman_element_unlock(element);
514 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
515 if (element->ipv4.nameserver == NULL)
516 return connman_element_get_value(element->parent,
518 connman_element_lock(element);
519 *((char **) value) = element->ipv4.nameserver;
520 connman_element_unlock(element);
527 int connman_element_register(struct connman_element *element,
528 struct connman_element *parent)
530 DBG("element %p name %s parent %p", element, element->name, parent);
532 if (connman_element_ref(element) == NULL)
535 connman_element_lock(element);
537 __connman_element_load(element);
539 if (element->name == NULL) {
540 switch (element->type) {
541 case CONNMAN_ELEMENT_TYPE_IPV4:
542 element->name = g_strdup("ipv4");
544 case CONNMAN_ELEMENT_TYPE_IPV6:
545 element->name = g_strdup("ipv6");
547 case CONNMAN_ELEMENT_TYPE_DHCP:
548 element->name = g_strdup("dhcp");
550 case CONNMAN_ELEMENT_TYPE_BOOTP:
551 element->name = g_strdup("bootp");
553 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
554 element->name = g_strdup("zeroconf");
556 case CONNMAN_ELEMENT_TYPE_RESOLVER:
557 element->name = g_strdup("resolver");
564 element->parent = parent;
566 connman_element_unlock(element);
568 if (thread_register != NULL)
569 g_thread_pool_push(thread_register, element, NULL);
574 void connman_element_unregister(struct connman_element *element)
576 DBG("element %p name %s", element, element->name);
578 if (thread_unregister != NULL)
579 g_thread_pool_push(thread_unregister, element, NULL);
582 void connman_element_update(struct connman_element *element)
584 DBG("element %p name %s", element, element->name);
586 g_static_rw_lock_reader_lock(&element_lock);
588 if (element->driver && element->driver->update)
589 element->driver->update(element);
591 g_static_rw_lock_reader_unlock(&element_lock);
593 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
594 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
595 DBUS_TYPE_OBJECT_PATH, &element->path,
599 static void register_element(gpointer data, gpointer user_data)
601 struct connman_element *element = data;
602 const gchar *basepath;
606 g_static_rw_lock_writer_lock(&element_lock);
608 connman_element_lock(element);
610 if (element->parent) {
611 node = g_node_find(element_root, G_PRE_ORDER,
612 G_TRAVERSE_ALL, element->parent);
613 basepath = element->parent->path;
615 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
616 element->subtype = element->parent->subtype;
622 element->path = g_strdup_printf("%s/%s", basepath, element->name);
624 connman_element_unlock(element);
626 DBG("element %p path %s", element, element->path);
628 g_node_append_data(node, element);
630 g_static_rw_lock_writer_unlock(&element_lock);
632 __connman_element_store(element);
634 g_dbus_register_interface(connection, element->path,
635 CONNMAN_ELEMENT_INTERFACE,
636 element_methods, NULL, NULL,
639 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
640 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
641 DBUS_TYPE_OBJECT_PATH, &element->path,
644 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
645 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
646 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
647 DBUS_TYPE_OBJECT_PATH, &element->path,
650 g_static_rw_lock_writer_lock(&element_lock);
652 for (list = driver_list; list; list = list->next) {
653 struct connman_driver *driver = list->data;
655 if (match_driver(element, driver) == FALSE)
658 DBG("driver %p name %s", driver, driver->name);
660 if (driver->probe(element) < 0)
663 connman_element_lock(element);
664 element->driver = driver;
665 connman_element_unlock(element);
668 g_static_rw_lock_writer_unlock(&element_lock);
671 static void unregister_element(gpointer data, gpointer user_data)
673 struct connman_element *element = data;
676 DBG("element %p name %s", element, element->name);
678 g_static_rw_lock_writer_lock(&element_lock);
680 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
682 if (element->driver) {
683 if (element->driver->remove)
684 element->driver->remove(element);
686 connman_element_lock(element);
687 element->driver = NULL;
688 connman_element_unlock(element);
693 g_node_destroy(node);
696 g_static_rw_lock_writer_unlock(&element_lock);
698 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
699 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
700 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
701 DBUS_TYPE_OBJECT_PATH, &element->path,
704 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
705 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
706 DBUS_TYPE_OBJECT_PATH, &element->path,
709 g_dbus_unregister_interface(connection, element->path,
710 CONNMAN_ELEMENT_INTERFACE);
712 connman_element_unref(element);
715 int __connman_element_init(DBusConnection *conn)
717 struct connman_element *element;
719 DBG("conn %p", conn);
721 connection = dbus_connection_ref(conn);
722 if (connection == NULL)
725 g_static_rw_lock_writer_lock(&element_lock);
727 element = connman_element_create();
729 element->name = g_strdup("root");
730 element->path = g_strdup("/");
731 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
733 element_root = g_node_new(element);
735 g_static_rw_lock_writer_unlock(&element_lock);
737 thread_register = g_thread_pool_new(register_element,
738 NULL, 1, FALSE, NULL);
739 thread_unregister = g_thread_pool_new(unregister_element,
740 NULL, 1, FALSE, NULL);
745 static gboolean free_driver(GNode *node, gpointer data)
747 struct connman_element *element = node->data;
749 DBG("element %p name %s", element, element->name);
751 if (element->driver) {
752 if (element->driver->remove)
753 element->driver->remove(element);
755 connman_element_lock(element);
756 element->driver = NULL;
757 connman_element_unlock(element);
763 static gboolean free_node(GNode *node, gpointer data)
765 struct connman_element *element = node->data;
767 DBG("element %p name %s", element, element->name);
769 if (g_node_depth(node) > 1)
770 g_thread_pool_push(thread_unregister, element, NULL);
775 void __connman_element_cleanup(void)
779 g_thread_pool_free(thread_register, TRUE, TRUE);
780 thread_register = NULL;
782 g_static_rw_lock_writer_lock(&element_lock);
783 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
785 g_static_rw_lock_writer_unlock(&element_lock);
787 g_static_rw_lock_writer_lock(&element_lock);
788 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
790 g_static_rw_lock_writer_unlock(&element_lock);
792 g_thread_pool_free(thread_unregister, FALSE, TRUE);
793 thread_unregister = NULL;
795 g_static_rw_lock_writer_lock(&element_lock);
796 g_node_destroy(element_root);
798 g_static_rw_lock_writer_unlock(&element_lock);
800 dbus_connection_unref(connection);