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 gchar *device_filter = NULL;
45 static const char *type2string(enum connman_element_type type)
48 case CONNMAN_ELEMENT_TYPE_UNKNOWN:
50 case CONNMAN_ELEMENT_TYPE_ROOT:
52 case CONNMAN_ELEMENT_TYPE_DEVICE:
54 case CONNMAN_ELEMENT_TYPE_NETWORK:
56 case CONNMAN_ELEMENT_TYPE_IPV4:
58 case CONNMAN_ELEMENT_TYPE_IPV6:
60 case CONNMAN_ELEMENT_TYPE_DHCP:
62 case CONNMAN_ELEMENT_TYPE_BOOTP:
64 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
66 case CONNMAN_ELEMENT_TYPE_RESOLVER:
68 case CONNMAN_ELEMENT_TYPE_INTERNET:
75 static const char *subtype2string(enum connman_element_subtype type)
78 case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
80 case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
82 case CONNMAN_ELEMENT_SUBTYPE_WIFI:
84 case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
86 case CONNMAN_ELEMENT_SUBTYPE_MODEM:
88 case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
95 static void append_entry(DBusMessageIter *dict,
96 const char *key, int type, void *val)
98 DBusMessageIter entry, value;
99 const char *signature;
101 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
104 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
107 case DBUS_TYPE_BOOLEAN:
108 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
110 case DBUS_TYPE_STRING:
111 signature = DBUS_TYPE_STRING_AS_STRING;
113 case DBUS_TYPE_UINT16:
114 signature = DBUS_TYPE_UINT16_AS_STRING;
116 case DBUS_TYPE_UINT32:
117 signature = DBUS_TYPE_UINT32_AS_STRING;
119 case DBUS_TYPE_OBJECT_PATH:
120 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
123 signature = DBUS_TYPE_VARIANT_AS_STRING;
127 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
129 dbus_message_iter_append_basic(&value, type, val);
130 dbus_message_iter_close_container(&entry, &value);
132 dbus_message_iter_close_container(dict, &entry);
135 static void append_property(DBusMessageIter *dict,
136 struct connman_property *property)
138 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
139 append_entry(dict, property->name, property->type,
145 static DBusMessage *get_properties(DBusConnection *conn,
146 DBusMessage *msg, void *data)
148 struct connman_element *element = data;
151 DBusMessageIter array, dict;
154 DBG("conn %p", conn);
156 reply = dbus_message_new_method_return(msg);
160 dbus_message_iter_init_append(reply, &array);
162 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
163 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
164 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
165 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
167 if (element->parent != NULL)
168 append_entry(&dict, "Parent",
169 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
171 str = type2string(element->type);
173 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
174 str = subtype2string(element->subtype);
176 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
178 append_entry(&dict, "Connected",
179 DBUS_TYPE_BOOLEAN, &element->connected);
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_connect(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->connect) {
245 DBG("Calling connect callback");
246 element->driver->connect(element);
249 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
252 static DBusMessage *do_disconnect(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->disconnect) {
263 DBG("Calling disconnect callback");
264 element->driver->disconnect(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 { "Connect", "", "", do_connect },
275 { "Disconnect", "", "", do_disconnect },
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->connected = 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));
629 element->parent = parent;
631 connman_element_unlock(element);
633 if (thread_register != NULL)
634 g_thread_pool_push(thread_register, element, NULL);
639 void connman_element_unregister(struct connman_element *element)
641 DBG("element %p name %s", element, element->name);
643 if (thread_unregister != NULL)
644 g_thread_pool_push(thread_unregister, element, NULL);
647 void connman_element_update(struct connman_element *element)
649 DBG("element %p name %s", element, element->name);
651 g_static_rw_lock_reader_lock(&element_lock);
653 if (element->driver && element->driver->update)
654 element->driver->update(element);
656 g_static_rw_lock_reader_unlock(&element_lock);
658 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
659 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
660 DBUS_TYPE_OBJECT_PATH, &element->path,
664 static void register_element(gpointer data, gpointer user_data)
666 struct connman_element *element = data;
667 const gchar *basepath;
671 g_static_rw_lock_writer_lock(&element_lock);
673 connman_element_lock(element);
675 if (element->parent) {
676 node = g_node_find(element_root, G_PRE_ORDER,
677 G_TRAVERSE_ALL, element->parent);
678 basepath = element->parent->path;
680 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
681 element->subtype = element->parent->subtype;
687 element->path = g_strdup_printf("%s/%s", basepath, element->name);
689 connman_element_unlock(element);
691 DBG("element %p path %s", element, element->path);
693 g_node_append_data(node, element);
695 if (g_dbus_register_interface(connection, element->path,
696 CONNMAN_ELEMENT_INTERFACE,
697 element_methods, element_signals,
698 NULL, element, NULL) == FALSE)
699 connman_error("Failed to register %s", element->path);
701 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
702 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
703 DBUS_TYPE_OBJECT_PATH, &element->path,
706 g_static_rw_lock_writer_unlock(&element_lock);
708 __connman_element_store(element);
710 g_static_rw_lock_writer_lock(&element_lock);
712 for (list = driver_list; list; list = list->next) {
713 struct connman_driver *driver = list->data;
715 if (match_driver(element, driver) == FALSE)
718 DBG("driver %p name %s", driver, driver->name);
720 if (driver->probe(element) < 0)
723 connman_element_lock(element);
724 element->driver = driver;
725 connman_element_unlock(element);
728 g_static_rw_lock_writer_unlock(&element_lock);
731 static gboolean remove_element(GNode *node, gpointer user_data)
733 struct connman_element *element = node->data;
735 DBG("element %p name %s", element, element->name);
737 if (element->driver) {
738 if (element->driver->remove)
739 element->driver->remove(element);
741 connman_element_lock(element);
742 element->driver = NULL;
743 connman_element_unlock(element);
748 g_node_destroy(node);
751 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
752 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
753 DBUS_TYPE_OBJECT_PATH, &element->path,
756 g_dbus_unregister_interface(connection, element->path,
757 CONNMAN_ELEMENT_INTERFACE);
759 connman_element_unref(element);
764 static void unregister_element(gpointer data, gpointer user_data)
766 struct connman_element *element = data;
769 DBG("element %p name %s", element, element->name);
771 g_static_rw_lock_writer_lock(&element_lock);
773 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
776 g_node_traverse(node, G_POST_ORDER,
777 G_TRAVERSE_ALL, -1, remove_element, NULL);
779 g_static_rw_lock_writer_unlock(&element_lock);
782 int __connman_element_init(DBusConnection *conn, const char *device)
784 struct connman_element *element;
786 DBG("conn %p", conn);
788 connection = dbus_connection_ref(conn);
789 if (connection == NULL)
792 device_filter = g_strdup(device);
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 g_free(device_filter);
871 dbus_connection_unref(connection);