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));
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_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 if (g_dbus_register_interface(connection, element->path,
699 CONNMAN_ELEMENT_INTERFACE,
700 element_methods, element_signals,
701 NULL, element, NULL) == FALSE)
702 connman_error("Failed to register %s", element->path);
704 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
705 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
706 DBUS_TYPE_OBJECT_PATH, &element->path,
709 g_static_rw_lock_writer_unlock(&element_lock);
711 __connman_element_store(element);
713 g_static_rw_lock_writer_lock(&element_lock);
715 for (list = driver_list; list; list = list->next) {
716 struct connman_driver *driver = list->data;
718 if (match_driver(element, driver) == FALSE)
721 DBG("driver %p name %s", driver, driver->name);
723 if (driver->probe(element) < 0)
726 connman_element_lock(element);
727 element->driver = driver;
728 connman_element_unlock(element);
731 g_static_rw_lock_writer_unlock(&element_lock);
734 static gboolean remove_element(GNode *node, gpointer user_data)
736 struct connman_element *element = node->data;
738 DBG("element %p name %s", element, element->name);
740 if (element->driver) {
741 if (element->driver->remove)
742 element->driver->remove(element);
744 connman_element_lock(element);
745 element->driver = NULL;
746 connman_element_unlock(element);
751 g_node_destroy(node);
754 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
755 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
756 DBUS_TYPE_OBJECT_PATH, &element->path,
759 g_dbus_unregister_interface(connection, element->path,
760 CONNMAN_ELEMENT_INTERFACE);
762 connman_element_unref(element);
767 static void unregister_element(gpointer data, gpointer user_data)
769 struct connman_element *element = data;
772 DBG("element %p name %s", element, element->name);
774 g_static_rw_lock_writer_lock(&element_lock);
776 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
779 g_node_traverse(node, G_POST_ORDER,
780 G_TRAVERSE_ALL, -1, remove_element, NULL);
782 g_static_rw_lock_writer_unlock(&element_lock);
785 int __connman_element_init(DBusConnection *conn, const char *device)
787 struct connman_element *element;
789 DBG("conn %p", conn);
791 connection = dbus_connection_ref(conn);
792 if (connection == NULL)
795 device_filter = g_strdup(device);
797 g_static_rw_lock_writer_lock(&element_lock);
799 element = connman_element_create();
801 element->name = g_strdup("root");
802 element->path = g_strdup("/");
803 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
805 element_root = g_node_new(element);
807 g_static_rw_lock_writer_unlock(&element_lock);
809 thread_register = g_thread_pool_new(register_element,
810 NULL, 1, FALSE, NULL);
811 thread_unregister = g_thread_pool_new(unregister_element,
812 NULL, 1, FALSE, NULL);
817 static gboolean free_driver(GNode *node, gpointer data)
819 struct connman_element *element = node->data;
821 DBG("element %p name %s", element, element->name);
823 if (element->driver) {
824 if (element->driver->remove)
825 element->driver->remove(element);
827 connman_element_lock(element);
828 element->driver = NULL;
829 connman_element_unlock(element);
835 static gboolean free_node(GNode *node, gpointer data)
837 struct connman_element *element = node->data;
839 DBG("element %p name %s", element, element->name);
841 if (g_node_depth(node) > 1)
842 g_thread_pool_push(thread_unregister, element, NULL);
847 void __connman_element_cleanup(void)
851 g_thread_pool_free(thread_register, TRUE, TRUE);
852 thread_register = NULL;
854 g_static_rw_lock_writer_lock(&element_lock);
855 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
857 g_static_rw_lock_writer_unlock(&element_lock);
859 g_static_rw_lock_writer_lock(&element_lock);
860 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
862 g_static_rw_lock_writer_unlock(&element_lock);
864 g_thread_pool_free(thread_unregister, FALSE, TRUE);
865 thread_unregister = NULL;
867 g_static_rw_lock_writer_lock(&element_lock);
868 g_node_destroy(element_root);
870 g_static_rw_lock_writer_unlock(&element_lock);
872 g_free(device_filter);
874 dbus_connection_unref(connection);