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_BOOLEAN:
106 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
108 case DBUS_TYPE_STRING:
109 signature = DBUS_TYPE_STRING_AS_STRING;
111 case DBUS_TYPE_UINT16:
112 signature = DBUS_TYPE_UINT16_AS_STRING;
114 case DBUS_TYPE_UINT32:
115 signature = DBUS_TYPE_UINT32_AS_STRING;
117 case DBUS_TYPE_OBJECT_PATH:
118 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
121 signature = DBUS_TYPE_VARIANT_AS_STRING;
125 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
127 dbus_message_iter_append_basic(&value, type, val);
128 dbus_message_iter_close_container(&entry, &value);
130 dbus_message_iter_close_container(dict, &entry);
133 static void append_property(DBusMessageIter *dict,
134 struct connman_property *property)
136 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
137 append_entry(dict, property->name, property->type,
143 static DBusMessage *get_properties(DBusConnection *conn,
144 DBusMessage *msg, void *data)
146 struct connman_element *element = data;
149 DBusMessageIter array, dict;
152 DBG("conn %p", conn);
154 reply = dbus_message_new_method_return(msg);
158 dbus_message_iter_init_append(reply, &array);
160 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
161 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
162 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
163 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
165 if (element->parent != NULL)
166 append_entry(&dict, "Parent",
167 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
169 str = type2string(element->type);
171 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
172 str = subtype2string(element->subtype);
174 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
176 append_entry(&dict, "Connected",
177 DBUS_TYPE_BOOLEAN, &element->connected);
179 if (element->priority > 0)
180 append_entry(&dict, "Priority",
181 DBUS_TYPE_UINT16, &element->priority);
183 if (element->network.identifier != NULL)
184 append_entry(&dict, "Identifier",
185 DBUS_TYPE_STRING, &element->network.identifier);
187 if (element->ipv4.address != NULL)
188 append_entry(&dict, "IPv4.Address",
189 DBUS_TYPE_STRING, &element->ipv4.address);
190 if (element->ipv4.netmask != NULL)
191 append_entry(&dict, "IPv4.Netmask",
192 DBUS_TYPE_STRING, &element->ipv4.netmask);
193 if (element->ipv4.gateway != NULL)
194 append_entry(&dict, "IPv4.Gateway",
195 DBUS_TYPE_STRING, &element->ipv4.gateway);
197 for (list = element->properties; list; list = list->next) {
198 struct connman_property *property = list->data;
200 append_property(&dict, property);
203 dbus_message_iter_close_container(&array, &dict);
208 static DBusMessage *set_property(DBusConnection *conn,
209 DBusMessage *msg, void *data)
211 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
214 static DBusMessage *do_update(DBusConnection *conn,
215 DBusMessage *msg, void *data)
217 struct connman_element *element = data;
219 DBG("conn %p", conn);
221 if (element->driver == NULL)
222 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
224 if (element->driver->update) {
225 DBG("Calling update callback");
226 element->driver->update(element);
229 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
232 static DBusMessage *do_connect(DBusConnection *conn,
233 DBusMessage *msg, void *data)
235 struct connman_element *element = data;
237 DBG("conn %p", conn);
239 if (element->driver == NULL)
240 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
242 if (element->driver->connect) {
243 DBG("Calling connect callback");
244 element->driver->connect(element);
247 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
250 static DBusMessage *do_disconnect(DBusConnection *conn,
251 DBusMessage *msg, void *data)
253 struct connman_element *element = data;
255 DBG("conn %p", conn);
257 if (element->driver == NULL)
258 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
260 if (element->driver->disconnect) {
261 DBG("Calling disconnect callback");
262 element->driver->disconnect(element);
265 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
268 static GDBusMethodTable element_methods[] = {
269 { "GetProperties", "", "a{sv}", get_properties },
270 { "SetProperty", "sv", "", set_property },
271 { "Update", "", "", do_update },
272 { "Connect", "", "", do_connect },
273 { "Disconnect", "", "", do_disconnect },
277 struct append_filter {
278 enum connman_element_type type;
279 DBusMessageIter *iter;
282 static gboolean append_path(GNode *node, gpointer data)
284 struct connman_element *element = node->data;
285 struct append_filter *filter = data;
287 DBG("element %p name %s", element, element->name);
289 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
292 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
293 filter->type != element->type)
296 dbus_message_iter_append_basic(filter->iter,
297 DBUS_TYPE_OBJECT_PATH, &element->path);
302 void __connman_element_list(enum connman_element_type type,
303 DBusMessageIter *iter)
305 struct append_filter filter = { type, iter };
309 g_static_rw_lock_reader_lock(&element_lock);
310 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
311 append_path, &filter);
312 g_static_rw_lock_reader_unlock(&element_lock);
315 static gint compare_priority(gconstpointer a, gconstpointer b)
317 const struct connman_driver *driver1 = a;
318 const struct connman_driver *driver2 = b;
320 return driver2->priority - driver1->priority;
323 static gboolean match_driver(struct connman_element *element,
324 struct connman_driver *driver)
326 if (element->type != driver->type &&
327 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
330 if (element->subtype == driver->subtype ||
331 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
337 static gboolean probe_driver(GNode *node, gpointer data)
339 struct connman_element *element = node->data;
340 struct connman_driver *driver = data;
342 DBG("element %p name %s", element, element->name);
344 if (!element->driver && match_driver(element, driver) == TRUE) {
345 if (driver->probe(element) < 0)
348 connman_element_lock(element);
349 element->driver = driver;
350 connman_element_unlock(element);
356 int connman_driver_register(struct connman_driver *driver)
358 DBG("driver %p name %s", driver, driver->name);
360 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
366 g_static_rw_lock_writer_lock(&element_lock);
368 driver_list = g_slist_insert_sorted(driver_list, driver,
371 if (element_root != NULL)
372 g_node_traverse(element_root, G_PRE_ORDER,
373 G_TRAVERSE_ALL, -1, probe_driver, driver);
375 g_static_rw_lock_writer_unlock(&element_lock);
380 static gboolean remove_driver(GNode *node, gpointer data)
382 struct connman_element *element = node->data;
383 struct connman_driver *driver = data;
385 DBG("element %p name %s", element, element->name);
387 if (element->driver == driver) {
389 driver->remove(element);
391 connman_element_lock(element);
392 element->driver = NULL;
393 connman_element_unlock(element);
399 void connman_driver_unregister(struct connman_driver *driver)
401 DBG("driver %p name %s", driver, driver->name);
403 g_static_rw_lock_writer_lock(&element_lock);
405 driver_list = g_slist_remove(driver_list, driver);
407 if (element_root != NULL)
408 g_node_traverse(element_root, G_POST_ORDER,
409 G_TRAVERSE_ALL, -1, remove_driver, driver);
411 g_static_rw_lock_writer_unlock(&element_lock);
414 struct connman_element *connman_element_create(void)
416 struct connman_element *element;
418 element = g_new0(struct connman_element, 1);
420 DBG("element %p", element);
422 element->refcount = 1;
424 g_static_mutex_init(&element->mutex);
426 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
427 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
428 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
430 element->connected = FALSE;
432 element->netdev.index = -1;
437 struct connman_element *connman_element_ref(struct connman_element *element)
439 DBG("element %p name %s refcount %d", element, element->name,
440 g_atomic_int_get(&element->refcount) + 1);
442 g_atomic_int_inc(&element->refcount);
447 void connman_element_unref(struct connman_element *element)
449 DBG("element %p name %s refcount %d", element, element->name,
450 g_atomic_int_get(&element->refcount) - 1);
452 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
455 for (list = element->properties; list; list = list->next) {
456 struct connman_property *property = list->data;
457 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
458 property->type == DBUS_TYPE_STRING)
459 g_free(property->value);
463 g_slist_free(element->properties);
465 g_free(element->ipv4.address);
466 g_free(element->ipv4.netmask);
467 g_free(element->ipv4.gateway);
468 g_free(element->ipv4.network);
469 g_free(element->ipv4.broadcast);
470 g_free(element->ipv4.nameserver);
471 g_free(element->network.identifier);
472 g_free(element->netdev.name);
473 g_free(element->path);
474 g_free(element->name);
479 int connman_element_add_static_property(struct connman_element *element,
480 const char *name, int type, const void *value)
482 struct connman_property *property;
484 DBG("element %p name %s", element, element->name);
486 if (type != DBUS_TYPE_STRING)
489 property = g_try_new0(struct connman_property, 1);
490 if (property == NULL)
493 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
495 property->name = g_strdup(name);
496 property->type = type;
498 DBG("name %s type %d value %p", name, type, value);
501 case DBUS_TYPE_STRING:
502 property->value = g_strdup(*((const char **) value));
506 connman_element_lock(element);
507 element->properties = g_slist_append(element->properties, property);
508 connman_element_unlock(element);
513 int connman_element_set_property(struct connman_element *element,
514 enum connman_property_type type, const void *value)
517 case CONNMAN_PROPERTY_TYPE_INVALID:
519 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
520 connman_element_lock(element);
521 g_free(element->ipv4.address);
522 element->ipv4.address = g_strdup(*((const char **) value));
523 connman_element_unlock(element);
525 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
526 connman_element_lock(element);
527 g_free(element->ipv4.netmask);
528 element->ipv4.netmask = g_strdup(*((const char **) value));
529 connman_element_unlock(element);
531 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
532 connman_element_lock(element);
533 g_free(element->ipv4.gateway);
534 element->ipv4.gateway = g_strdup(*((const char **) value));
535 connman_element_unlock(element);
537 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
538 connman_element_lock(element);
539 g_free(element->ipv4.nameserver);
540 element->ipv4.nameserver = g_strdup(*((const char **) value));
541 connman_element_unlock(element);
545 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
546 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
547 DBUS_TYPE_OBJECT_PATH, &element->path,
553 int connman_element_get_value(struct connman_element *element,
554 enum connman_property_type type, void *value)
556 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
560 case CONNMAN_PROPERTY_TYPE_INVALID:
562 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
563 if (element->ipv4.address == NULL)
564 return connman_element_get_value(element->parent,
566 connman_element_lock(element);
567 *((char **) value) = element->ipv4.address;
568 connman_element_unlock(element);
570 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
571 if (element->ipv4.netmask == NULL)
572 return connman_element_get_value(element->parent,
574 connman_element_lock(element);
575 *((char **) value) = element->ipv4.netmask;
576 connman_element_unlock(element);
578 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
579 if (element->ipv4.gateway == NULL)
580 return connman_element_get_value(element->parent,
582 connman_element_lock(element);
583 *((char **) value) = element->ipv4.gateway;
584 connman_element_unlock(element);
586 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
587 if (element->ipv4.nameserver == NULL)
588 return connman_element_get_value(element->parent,
590 connman_element_lock(element);
591 *((char **) value) = element->ipv4.nameserver;
592 connman_element_unlock(element);
599 int connman_element_register(struct connman_element *element,
600 struct connman_element *parent)
602 DBG("element %p name %s parent %p", element, element->name, parent);
604 if (connman_element_ref(element) == NULL)
607 connman_element_lock(element);
609 __connman_element_load(element);
611 if (element->name == NULL) {
612 switch (element->type) {
613 case CONNMAN_ELEMENT_TYPE_IPV4:
614 element->name = g_strdup("ipv4");
616 case CONNMAN_ELEMENT_TYPE_IPV6:
617 element->name = g_strdup("ipv6");
619 case CONNMAN_ELEMENT_TYPE_DHCP:
620 element->name = g_strdup("dhcp");
622 case CONNMAN_ELEMENT_TYPE_BOOTP:
623 element->name = g_strdup("bootp");
625 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
626 element->name = g_strdup("zeroconf");
628 case CONNMAN_ELEMENT_TYPE_RESOLVER:
629 element->name = g_strdup("resolver");
631 case CONNMAN_ELEMENT_TYPE_INTERNET:
632 element->name = g_strdup("internet");
639 element->parent = parent;
641 connman_element_unlock(element);
643 if (thread_register != NULL)
644 g_thread_pool_push(thread_register, element, NULL);
649 void connman_element_unregister(struct connman_element *element)
651 DBG("element %p name %s", element, element->name);
653 if (thread_unregister != NULL)
654 g_thread_pool_push(thread_unregister, element, NULL);
657 void connman_element_update(struct connman_element *element)
659 DBG("element %p name %s", element, element->name);
661 g_static_rw_lock_reader_lock(&element_lock);
663 if (element->driver && element->driver->update)
664 element->driver->update(element);
666 g_static_rw_lock_reader_unlock(&element_lock);
668 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
669 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
670 DBUS_TYPE_OBJECT_PATH, &element->path,
674 static void register_element(gpointer data, gpointer user_data)
676 struct connman_element *element = data;
677 const gchar *basepath;
681 g_static_rw_lock_writer_lock(&element_lock);
683 connman_element_lock(element);
685 if (element->parent) {
686 node = g_node_find(element_root, G_PRE_ORDER,
687 G_TRAVERSE_ALL, element->parent);
688 basepath = element->parent->path;
690 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
691 element->subtype = element->parent->subtype;
697 element->path = g_strdup_printf("%s/%s", basepath, element->name);
699 connman_element_unlock(element);
701 DBG("element %p path %s", element, element->path);
703 g_node_append_data(node, element);
705 g_static_rw_lock_writer_unlock(&element_lock);
707 __connman_element_store(element);
709 if (g_dbus_register_interface(connection, element->path,
710 CONNMAN_ELEMENT_INTERFACE,
711 element_methods, NULL, NULL,
712 element, NULL) == FALSE)
713 connman_error("Failed to register %s", element->path);
715 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
716 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
717 DBUS_TYPE_OBJECT_PATH, &element->path,
720 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
721 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
722 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
723 DBUS_TYPE_OBJECT_PATH, &element->path,
726 g_static_rw_lock_writer_lock(&element_lock);
728 for (list = driver_list; list; list = list->next) {
729 struct connman_driver *driver = list->data;
731 if (match_driver(element, driver) == FALSE)
734 DBG("driver %p name %s", driver, driver->name);
736 if (driver->probe(element) < 0)
739 connman_element_lock(element);
740 element->driver = driver;
741 connman_element_unlock(element);
744 g_static_rw_lock_writer_unlock(&element_lock);
747 static void unregister_element(gpointer data, gpointer user_data)
749 struct connman_element *element = data;
752 DBG("element %p name %s", element, element->name);
754 g_static_rw_lock_writer_lock(&element_lock);
756 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
758 if (element->driver) {
759 if (element->driver->remove)
760 element->driver->remove(element);
762 connman_element_lock(element);
763 element->driver = NULL;
764 connman_element_unlock(element);
769 g_node_destroy(node);
772 g_static_rw_lock_writer_unlock(&element_lock);
774 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
775 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
776 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
777 DBUS_TYPE_OBJECT_PATH, &element->path,
780 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
781 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
782 DBUS_TYPE_OBJECT_PATH, &element->path,
785 g_dbus_unregister_interface(connection, element->path,
786 CONNMAN_ELEMENT_INTERFACE);
788 connman_element_unref(element);
791 int __connman_element_init(DBusConnection *conn)
793 struct connman_element *element;
795 DBG("conn %p", conn);
797 connection = dbus_connection_ref(conn);
798 if (connection == NULL)
801 g_static_rw_lock_writer_lock(&element_lock);
803 element = connman_element_create();
805 element->name = g_strdup("root");
806 element->path = g_strdup("/");
807 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
809 element_root = g_node_new(element);
811 g_static_rw_lock_writer_unlock(&element_lock);
813 thread_register = g_thread_pool_new(register_element,
814 NULL, 1, FALSE, NULL);
815 thread_unregister = g_thread_pool_new(unregister_element,
816 NULL, 1, FALSE, NULL);
821 static gboolean free_driver(GNode *node, gpointer data)
823 struct connman_element *element = node->data;
825 DBG("element %p name %s", element, element->name);
827 if (element->driver) {
828 if (element->driver->remove)
829 element->driver->remove(element);
831 connman_element_lock(element);
832 element->driver = NULL;
833 connman_element_unlock(element);
839 static gboolean free_node(GNode *node, gpointer data)
841 struct connman_element *element = node->data;
843 DBG("element %p name %s", element, element->name);
845 if (g_node_depth(node) > 1)
846 g_thread_pool_push(thread_unregister, element, NULL);
851 void __connman_element_cleanup(void)
855 g_thread_pool_free(thread_register, TRUE, TRUE);
856 thread_register = NULL;
858 g_static_rw_lock_writer_lock(&element_lock);
859 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
861 g_static_rw_lock_writer_unlock(&element_lock);
863 g_static_rw_lock_writer_lock(&element_lock);
864 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
866 g_static_rw_lock_writer_unlock(&element_lock);
868 g_thread_pool_free(thread_unregister, FALSE, TRUE);
869 thread_unregister = NULL;
871 g_static_rw_lock_writer_lock(&element_lock);
872 g_node_destroy(element_root);
874 g_static_rw_lock_writer_unlock(&element_lock);
876 dbus_connection_unref(connection);