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 *do_update(DBusConnection *conn,
209 DBusMessage *msg, void *data)
211 struct connman_element *element = data;
213 DBG("conn %p", conn);
215 if (element->driver == NULL)
216 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
218 if (element->driver->update) {
219 DBG("Calling update callback");
220 element->driver->update(element);
223 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
226 static DBusMessage *do_connect(DBusConnection *conn,
227 DBusMessage *msg, void *data)
229 struct connman_element *element = data;
231 DBG("conn %p", conn);
233 if (element->driver == NULL)
234 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
236 if (element->driver->connect) {
237 DBG("Calling connect callback");
238 element->driver->connect(element);
241 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
244 static DBusMessage *do_disconnect(DBusConnection *conn,
245 DBusMessage *msg, void *data)
247 struct connman_element *element = data;
249 DBG("conn %p", conn);
251 if (element->driver == NULL)
252 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
254 if (element->driver->disconnect) {
255 DBG("Calling disconnect callback");
256 element->driver->disconnect(element);
259 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
262 static GDBusMethodTable element_methods[] = {
263 { "GetProperties", "", "a{sv}", get_properties },
264 { "Update", "", "", do_update },
265 { "Connect", "", "", do_connect },
266 { "Disconnect", "", "", do_disconnect },
270 struct append_filter {
271 enum connman_element_type type;
272 DBusMessageIter *iter;
275 static gboolean append_path(GNode *node, gpointer data)
277 struct connman_element *element = node->data;
278 struct append_filter *filter = data;
280 DBG("element %p name %s", element, element->name);
282 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
285 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
286 filter->type != element->type)
289 dbus_message_iter_append_basic(filter->iter,
290 DBUS_TYPE_OBJECT_PATH, &element->path);
295 void __connman_element_list(enum connman_element_type type,
296 DBusMessageIter *iter)
298 struct append_filter filter = { type, iter };
302 g_static_rw_lock_reader_lock(&element_lock);
303 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
304 append_path, &filter);
305 g_static_rw_lock_reader_unlock(&element_lock);
308 static gint compare_priority(gconstpointer a, gconstpointer b)
310 const struct connman_driver *driver1 = a;
311 const struct connman_driver *driver2 = b;
313 return driver2->priority - driver1->priority;
316 static gboolean match_driver(struct connman_element *element,
317 struct connman_driver *driver)
319 if (element->type != driver->type &&
320 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
323 if (element->subtype == driver->subtype ||
324 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
330 static gboolean probe_driver(GNode *node, gpointer data)
332 struct connman_element *element = node->data;
333 struct connman_driver *driver = data;
335 DBG("element %p name %s", element, element->name);
337 if (!element->driver && match_driver(element, driver) == TRUE) {
338 if (driver->probe(element) < 0)
341 connman_element_lock(element);
342 element->driver = driver;
343 connman_element_unlock(element);
349 int connman_driver_register(struct connman_driver *driver)
351 DBG("driver %p name %s", driver, driver->name);
353 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
359 g_static_rw_lock_writer_lock(&element_lock);
361 driver_list = g_slist_insert_sorted(driver_list, driver,
364 if (element_root != NULL)
365 g_node_traverse(element_root, G_PRE_ORDER,
366 G_TRAVERSE_ALL, -1, probe_driver, driver);
368 g_static_rw_lock_writer_unlock(&element_lock);
373 static gboolean remove_driver(GNode *node, gpointer data)
375 struct connman_element *element = node->data;
376 struct connman_driver *driver = data;
378 DBG("element %p name %s", element, element->name);
380 if (element->driver == driver) {
382 driver->remove(element);
384 connman_element_lock(element);
385 element->driver = NULL;
386 connman_element_unlock(element);
392 void connman_driver_unregister(struct connman_driver *driver)
394 DBG("driver %p name %s", driver, driver->name);
396 g_static_rw_lock_writer_lock(&element_lock);
398 driver_list = g_slist_remove(driver_list, driver);
400 if (element_root != NULL)
401 g_node_traverse(element_root, G_POST_ORDER,
402 G_TRAVERSE_ALL, -1, remove_driver, driver);
404 g_static_rw_lock_writer_unlock(&element_lock);
407 struct connman_element *connman_element_create(void)
409 struct connman_element *element;
411 element = g_new0(struct connman_element, 1);
413 DBG("element %p", element);
415 element->refcount = 1;
417 g_static_mutex_init(&element->mutex);
419 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
420 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
421 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
423 element->connected = FALSE;
425 element->netdev.index = -1;
430 struct connman_element *connman_element_ref(struct connman_element *element)
432 DBG("element %p name %s refcount %d", element, element->name,
433 g_atomic_int_get(&element->refcount) + 1);
435 g_atomic_int_inc(&element->refcount);
440 void connman_element_unref(struct connman_element *element)
442 DBG("element %p name %s refcount %d", element, element->name,
443 g_atomic_int_get(&element->refcount) - 1);
445 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
448 for (list = element->properties; list; list = list->next) {
449 struct connman_property *property = list->data;
450 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
451 property->type == DBUS_TYPE_STRING)
452 g_free(property->value);
456 g_slist_free(element->properties);
458 g_free(element->ipv4.address);
459 g_free(element->ipv4.netmask);
460 g_free(element->ipv4.gateway);
461 g_free(element->ipv4.network);
462 g_free(element->ipv4.broadcast);
463 g_free(element->ipv4.nameserver);
464 g_free(element->network.identifier);
465 g_free(element->netdev.name);
466 g_free(element->path);
467 g_free(element->name);
472 int connman_element_add_static_property(struct connman_element *element,
473 const char *name, int type, const void *value)
475 struct connman_property *property;
477 DBG("element %p name %s", element, element->name);
479 if (type != DBUS_TYPE_STRING)
482 property = g_try_new0(struct connman_property, 1);
483 if (property == NULL)
486 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
488 property->name = g_strdup(name);
489 property->type = type;
491 DBG("name %s type %d value %p", name, type, value);
494 case DBUS_TYPE_STRING:
495 property->value = g_strdup(*((const char **) value));
499 connman_element_lock(element);
500 element->properties = g_slist_append(element->properties, property);
501 connman_element_unlock(element);
506 int connman_element_set_property(struct connman_element *element,
507 enum connman_property_type type, const void *value)
510 case CONNMAN_PROPERTY_TYPE_INVALID:
512 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
513 connman_element_lock(element);
514 g_free(element->ipv4.address);
515 element->ipv4.address = g_strdup(*((const char **) value));
516 connman_element_unlock(element);
518 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
519 connman_element_lock(element);
520 g_free(element->ipv4.netmask);
521 element->ipv4.netmask = g_strdup(*((const char **) value));
522 connman_element_unlock(element);
524 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
525 connman_element_lock(element);
526 g_free(element->ipv4.gateway);
527 element->ipv4.gateway = g_strdup(*((const char **) value));
528 connman_element_unlock(element);
530 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
531 connman_element_lock(element);
532 g_free(element->ipv4.nameserver);
533 element->ipv4.nameserver = g_strdup(*((const char **) value));
534 connman_element_unlock(element);
538 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
539 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
540 DBUS_TYPE_OBJECT_PATH, &element->path,
546 int connman_element_get_value(struct connman_element *element,
547 enum connman_property_type type, void *value)
549 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
553 case CONNMAN_PROPERTY_TYPE_INVALID:
555 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
556 if (element->ipv4.address == NULL)
557 return connman_element_get_value(element->parent,
559 connman_element_lock(element);
560 *((char **) value) = element->ipv4.address;
561 connman_element_unlock(element);
563 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
564 if (element->ipv4.netmask == NULL)
565 return connman_element_get_value(element->parent,
567 connman_element_lock(element);
568 *((char **) value) = element->ipv4.netmask;
569 connman_element_unlock(element);
571 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
572 if (element->ipv4.gateway == NULL)
573 return connman_element_get_value(element->parent,
575 connman_element_lock(element);
576 *((char **) value) = element->ipv4.gateway;
577 connman_element_unlock(element);
579 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
580 if (element->ipv4.nameserver == NULL)
581 return connman_element_get_value(element->parent,
583 connman_element_lock(element);
584 *((char **) value) = element->ipv4.nameserver;
585 connman_element_unlock(element);
592 int connman_element_register(struct connman_element *element,
593 struct connman_element *parent)
595 DBG("element %p name %s parent %p", element, element->name, parent);
597 if (connman_element_ref(element) == NULL)
600 connman_element_lock(element);
602 __connman_element_load(element);
604 if (element->name == NULL) {
605 switch (element->type) {
606 case CONNMAN_ELEMENT_TYPE_IPV4:
607 element->name = g_strdup("ipv4");
609 case CONNMAN_ELEMENT_TYPE_IPV6:
610 element->name = g_strdup("ipv6");
612 case CONNMAN_ELEMENT_TYPE_DHCP:
613 element->name = g_strdup("dhcp");
615 case CONNMAN_ELEMENT_TYPE_BOOTP:
616 element->name = g_strdup("bootp");
618 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
619 element->name = g_strdup("zeroconf");
621 case CONNMAN_ELEMENT_TYPE_RESOLVER:
622 element->name = g_strdup("resolver");
624 case CONNMAN_ELEMENT_TYPE_INTERNET:
625 element->name = g_strdup("internet");
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_update(struct connman_element *element)
652 DBG("element %p name %s", element, element->name);
654 g_static_rw_lock_reader_lock(&element_lock);
656 if (element->driver && element->driver->update)
657 element->driver->update(element);
659 g_static_rw_lock_reader_unlock(&element_lock);
661 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
662 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
663 DBUS_TYPE_OBJECT_PATH, &element->path,
667 static void register_element(gpointer data, gpointer user_data)
669 struct connman_element *element = data;
670 const gchar *basepath;
674 g_static_rw_lock_writer_lock(&element_lock);
676 connman_element_lock(element);
678 if (element->parent) {
679 node = g_node_find(element_root, G_PRE_ORDER,
680 G_TRAVERSE_ALL, element->parent);
681 basepath = element->parent->path;
683 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
684 element->subtype = element->parent->subtype;
690 element->path = g_strdup_printf("%s/%s", basepath, element->name);
692 connman_element_unlock(element);
694 DBG("element %p path %s", element, element->path);
696 g_node_append_data(node, element);
698 g_static_rw_lock_writer_unlock(&element_lock);
700 __connman_element_store(element);
702 if (g_dbus_register_interface(connection, element->path,
703 CONNMAN_ELEMENT_INTERFACE,
704 element_methods, NULL, NULL,
705 element, NULL) == FALSE)
706 connman_error("Failed to register %s", element->path);
708 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
709 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
710 DBUS_TYPE_OBJECT_PATH, &element->path,
713 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
714 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
715 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
716 DBUS_TYPE_OBJECT_PATH, &element->path,
719 g_static_rw_lock_writer_lock(&element_lock);
721 for (list = driver_list; list; list = list->next) {
722 struct connman_driver *driver = list->data;
724 if (match_driver(element, driver) == FALSE)
727 DBG("driver %p name %s", driver, driver->name);
729 if (driver->probe(element) < 0)
732 connman_element_lock(element);
733 element->driver = driver;
734 connman_element_unlock(element);
737 g_static_rw_lock_writer_unlock(&element_lock);
740 static void unregister_element(gpointer data, gpointer user_data)
742 struct connman_element *element = data;
745 DBG("element %p name %s", element, element->name);
747 g_static_rw_lock_writer_lock(&element_lock);
749 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
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);
762 g_node_destroy(node);
765 g_static_rw_lock_writer_unlock(&element_lock);
767 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
768 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
769 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
770 DBUS_TYPE_OBJECT_PATH, &element->path,
773 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
774 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
775 DBUS_TYPE_OBJECT_PATH, &element->path,
778 g_dbus_unregister_interface(connection, element->path,
779 CONNMAN_ELEMENT_INTERFACE);
781 connman_element_unref(element);
784 int __connman_element_init(DBusConnection *conn)
786 struct connman_element *element;
788 DBG("conn %p", conn);
790 connection = dbus_connection_ref(conn);
791 if (connection == NULL)
794 g_static_rw_lock_writer_lock(&element_lock);
796 element = connman_element_create();
798 element->name = g_strdup("root");
799 element->path = g_strdup("/");
800 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
802 element_root = g_node_new(element);
804 g_static_rw_lock_writer_unlock(&element_lock);
806 thread_register = g_thread_pool_new(register_element,
807 NULL, 1, FALSE, NULL);
808 thread_unregister = g_thread_pool_new(unregister_element,
809 NULL, 1, FALSE, NULL);
814 static gboolean free_driver(GNode *node, gpointer data)
816 struct connman_element *element = node->data;
818 DBG("element %p name %s", element, element->name);
820 if (element->driver) {
821 if (element->driver->remove)
822 element->driver->remove(element);
824 connman_element_lock(element);
825 element->driver = NULL;
826 connman_element_unlock(element);
832 static gboolean free_node(GNode *node, gpointer data)
834 struct connman_element *element = node->data;
836 DBG("element %p name %s", element, element->name);
838 if (g_node_depth(node) > 1)
839 g_thread_pool_push(thread_unregister, element, NULL);
844 void __connman_element_cleanup(void)
848 g_thread_pool_free(thread_register, TRUE, TRUE);
849 thread_register = NULL;
851 g_static_rw_lock_writer_lock(&element_lock);
852 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
854 g_static_rw_lock_writer_unlock(&element_lock);
856 g_static_rw_lock_writer_lock(&element_lock);
857 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
859 g_static_rw_lock_writer_unlock(&element_lock);
861 g_thread_pool_free(thread_unregister, FALSE, TRUE);
862 thread_unregister = NULL;
864 g_static_rw_lock_writer_lock(&element_lock);
865 g_node_destroy(element_root);
867 g_static_rw_lock_writer_unlock(&element_lock);
869 dbus_connection_unref(connection);