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_connect(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->connect) {
219 DBG("Calling connect callback");
220 element->driver->connect(element);
223 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
226 static DBusMessage *do_disconnect(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->disconnect) {
237 DBG("Calling disconnect callback");
238 element->driver->disconnect(element);
241 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
244 static GDBusMethodTable element_methods[] = {
245 { "GetProperties", "", "a{sv}", get_properties },
246 { "Connect", "", "", do_connect },
247 { "Disconnect", "", "", do_disconnect },
251 struct append_filter {
252 enum connman_element_type type;
253 DBusMessageIter *iter;
256 static gboolean append_path(GNode *node, gpointer data)
258 struct connman_element *element = node->data;
259 struct append_filter *filter = data;
261 DBG("element %p name %s", element, element->name);
263 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
266 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
267 filter->type != element->type)
270 dbus_message_iter_append_basic(filter->iter,
271 DBUS_TYPE_OBJECT_PATH, &element->path);
276 void __connman_element_list(enum connman_element_type type,
277 DBusMessageIter *iter)
279 struct append_filter filter = { type, iter };
283 g_static_rw_lock_reader_lock(&element_lock);
284 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
285 append_path, &filter);
286 g_static_rw_lock_reader_unlock(&element_lock);
289 static gint compare_priority(gconstpointer a, gconstpointer b)
291 const struct connman_driver *driver1 = a;
292 const struct connman_driver *driver2 = b;
294 return driver2->priority - driver1->priority;
297 static gboolean match_driver(struct connman_element *element,
298 struct connman_driver *driver)
300 if (element->type != driver->type &&
301 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
304 if (element->subtype == driver->subtype ||
305 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
311 static gboolean probe_driver(GNode *node, gpointer data)
313 struct connman_element *element = node->data;
314 struct connman_driver *driver = data;
316 DBG("element %p name %s", element, element->name);
318 if (!element->driver && match_driver(element, driver) == TRUE) {
319 if (driver->probe(element) < 0)
322 connman_element_lock(element);
323 element->driver = driver;
324 connman_element_unlock(element);
330 int connman_driver_register(struct connman_driver *driver)
332 DBG("driver %p name %s", driver, driver->name);
334 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
340 g_static_rw_lock_writer_lock(&element_lock);
342 driver_list = g_slist_insert_sorted(driver_list, driver,
345 if (element_root != NULL)
346 g_node_traverse(element_root, G_PRE_ORDER,
347 G_TRAVERSE_ALL, -1, probe_driver, driver);
349 g_static_rw_lock_writer_unlock(&element_lock);
354 static gboolean remove_driver(GNode *node, gpointer data)
356 struct connman_element *element = node->data;
357 struct connman_driver *driver = data;
359 DBG("element %p name %s", element, element->name);
361 if (element->driver == driver) {
363 driver->remove(element);
365 connman_element_lock(element);
366 element->driver = NULL;
367 connman_element_unlock(element);
373 void connman_driver_unregister(struct connman_driver *driver)
375 DBG("driver %p name %s", driver, driver->name);
377 g_static_rw_lock_writer_lock(&element_lock);
379 driver_list = g_slist_remove(driver_list, driver);
381 if (element_root != NULL)
382 g_node_traverse(element_root, G_POST_ORDER,
383 G_TRAVERSE_ALL, -1, remove_driver, driver);
385 g_static_rw_lock_writer_unlock(&element_lock);
388 struct connman_element *connman_element_create(void)
390 struct connman_element *element;
392 element = g_new0(struct connman_element, 1);
394 DBG("element %p", element);
396 element->refcount = 1;
398 g_static_mutex_init(&element->mutex);
400 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
401 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
402 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
404 element->connected = FALSE;
406 element->netdev.index = -1;
411 struct connman_element *connman_element_ref(struct connman_element *element)
413 DBG("element %p name %s refcount %d", element, element->name,
414 g_atomic_int_get(&element->refcount) + 1);
416 g_atomic_int_inc(&element->refcount);
421 void connman_element_unref(struct connman_element *element)
423 DBG("element %p name %s refcount %d", element, element->name,
424 g_atomic_int_get(&element->refcount) - 1);
426 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
429 for (list = element->properties; list; list = list->next) {
430 struct connman_property *property = list->data;
431 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
432 property->type == DBUS_TYPE_STRING)
433 g_free(property->value);
437 g_slist_free(element->properties);
439 g_free(element->ipv4.address);
440 g_free(element->ipv4.netmask);
441 g_free(element->ipv4.gateway);
442 g_free(element->ipv4.network);
443 g_free(element->ipv4.broadcast);
444 g_free(element->ipv4.nameserver);
445 g_free(element->network.identifier);
446 g_free(element->netdev.name);
447 g_free(element->path);
448 g_free(element->name);
453 int connman_element_add_static_property(struct connman_element *element,
454 const char *name, int type, const void *value)
456 struct connman_property *property;
458 DBG("element %p name %s", element, element->name);
460 if (type != DBUS_TYPE_STRING)
463 property = g_try_new0(struct connman_property, 1);
464 if (property == NULL)
467 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
469 property->name = g_strdup(name);
470 property->type = type;
472 DBG("name %s type %d value %p", name, type, value);
475 case DBUS_TYPE_STRING:
476 property->value = g_strdup(*((const char **) value));
480 connman_element_lock(element);
481 element->properties = g_slist_append(element->properties, property);
482 connman_element_unlock(element);
487 int connman_element_set_property(struct connman_element *element,
488 enum connman_property_type type, const void *value)
491 case CONNMAN_PROPERTY_TYPE_INVALID:
493 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
494 connman_element_lock(element);
495 g_free(element->ipv4.address);
496 element->ipv4.address = g_strdup(*((const char **) value));
497 connman_element_unlock(element);
499 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
500 connman_element_lock(element);
501 g_free(element->ipv4.netmask);
502 element->ipv4.netmask = g_strdup(*((const char **) value));
503 connman_element_unlock(element);
505 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
506 connman_element_lock(element);
507 g_free(element->ipv4.gateway);
508 element->ipv4.gateway = g_strdup(*((const char **) value));
509 connman_element_unlock(element);
511 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
512 connman_element_lock(element);
513 g_free(element->ipv4.nameserver);
514 element->ipv4.nameserver = g_strdup(*((const char **) value));
515 connman_element_unlock(element);
519 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
520 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
521 DBUS_TYPE_OBJECT_PATH, &element->path,
527 int connman_element_get_value(struct connman_element *element,
528 enum connman_property_type type, void *value)
530 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
534 case CONNMAN_PROPERTY_TYPE_INVALID:
536 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
537 if (element->ipv4.address == NULL)
538 return connman_element_get_value(element->parent,
540 connman_element_lock(element);
541 *((char **) value) = element->ipv4.address;
542 connman_element_unlock(element);
544 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
545 if (element->ipv4.netmask == NULL)
546 return connman_element_get_value(element->parent,
548 connman_element_lock(element);
549 *((char **) value) = element->ipv4.netmask;
550 connman_element_unlock(element);
552 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
553 if (element->ipv4.gateway == NULL)
554 return connman_element_get_value(element->parent,
556 connman_element_lock(element);
557 *((char **) value) = element->ipv4.gateway;
558 connman_element_unlock(element);
560 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
561 if (element->ipv4.nameserver == NULL)
562 return connman_element_get_value(element->parent,
564 connman_element_lock(element);
565 *((char **) value) = element->ipv4.nameserver;
566 connman_element_unlock(element);
573 int connman_element_register(struct connman_element *element,
574 struct connman_element *parent)
576 DBG("element %p name %s parent %p", element, element->name, parent);
578 if (connman_element_ref(element) == NULL)
581 connman_element_lock(element);
583 __connman_element_load(element);
585 if (element->name == NULL) {
586 switch (element->type) {
587 case CONNMAN_ELEMENT_TYPE_IPV4:
588 element->name = g_strdup("ipv4");
590 case CONNMAN_ELEMENT_TYPE_IPV6:
591 element->name = g_strdup("ipv6");
593 case CONNMAN_ELEMENT_TYPE_DHCP:
594 element->name = g_strdup("dhcp");
596 case CONNMAN_ELEMENT_TYPE_BOOTP:
597 element->name = g_strdup("bootp");
599 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
600 element->name = g_strdup("zeroconf");
602 case CONNMAN_ELEMENT_TYPE_RESOLVER:
603 element->name = g_strdup("resolver");
605 case CONNMAN_ELEMENT_TYPE_INTERNET:
606 element->name = g_strdup("internet");
613 element->parent = parent;
615 connman_element_unlock(element);
617 if (thread_register != NULL)
618 g_thread_pool_push(thread_register, element, NULL);
623 void connman_element_unregister(struct connman_element *element)
625 DBG("element %p name %s", element, element->name);
627 if (thread_unregister != NULL)
628 g_thread_pool_push(thread_unregister, element, NULL);
631 void connman_element_update(struct connman_element *element)
633 DBG("element %p name %s", element, element->name);
635 g_static_rw_lock_reader_lock(&element_lock);
637 if (element->driver && element->driver->update)
638 element->driver->update(element);
640 g_static_rw_lock_reader_unlock(&element_lock);
642 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
643 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
644 DBUS_TYPE_OBJECT_PATH, &element->path,
648 static void register_element(gpointer data, gpointer user_data)
650 struct connman_element *element = data;
651 const gchar *basepath;
655 g_static_rw_lock_writer_lock(&element_lock);
657 connman_element_lock(element);
659 if (element->parent) {
660 node = g_node_find(element_root, G_PRE_ORDER,
661 G_TRAVERSE_ALL, element->parent);
662 basepath = element->parent->path;
664 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
665 element->subtype = element->parent->subtype;
671 element->path = g_strdup_printf("%s/%s", basepath, element->name);
673 connman_element_unlock(element);
675 DBG("element %p path %s", element, element->path);
677 g_node_append_data(node, element);
679 g_static_rw_lock_writer_unlock(&element_lock);
681 __connman_element_store(element);
683 if (g_dbus_register_interface(connection, element->path,
684 CONNMAN_ELEMENT_INTERFACE,
685 element_methods, NULL, NULL,
686 element, NULL) == FALSE)
687 connman_error("Failed to register %s", element->path);
689 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
690 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
691 DBUS_TYPE_OBJECT_PATH, &element->path,
694 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
695 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
696 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
697 DBUS_TYPE_OBJECT_PATH, &element->path,
700 g_static_rw_lock_writer_lock(&element_lock);
702 for (list = driver_list; list; list = list->next) {
703 struct connman_driver *driver = list->data;
705 if (match_driver(element, driver) == FALSE)
708 DBG("driver %p name %s", driver, driver->name);
710 if (driver->probe(element) < 0)
713 connman_element_lock(element);
714 element->driver = driver;
715 connman_element_unlock(element);
718 g_static_rw_lock_writer_unlock(&element_lock);
721 static void unregister_element(gpointer data, gpointer user_data)
723 struct connman_element *element = data;
726 DBG("element %p name %s", element, element->name);
728 g_static_rw_lock_writer_lock(&element_lock);
730 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
732 if (element->driver) {
733 if (element->driver->remove)
734 element->driver->remove(element);
736 connman_element_lock(element);
737 element->driver = NULL;
738 connman_element_unlock(element);
743 g_node_destroy(node);
746 g_static_rw_lock_writer_unlock(&element_lock);
748 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
749 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
750 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
751 DBUS_TYPE_OBJECT_PATH, &element->path,
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);
765 int __connman_element_init(DBusConnection *conn)
767 struct connman_element *element;
769 DBG("conn %p", conn);
771 connection = dbus_connection_ref(conn);
772 if (connection == NULL)
775 g_static_rw_lock_writer_lock(&element_lock);
777 element = connman_element_create();
779 element->name = g_strdup("root");
780 element->path = g_strdup("/");
781 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
783 element_root = g_node_new(element);
785 g_static_rw_lock_writer_unlock(&element_lock);
787 thread_register = g_thread_pool_new(register_element,
788 NULL, 1, FALSE, NULL);
789 thread_unregister = g_thread_pool_new(unregister_element,
790 NULL, 1, FALSE, NULL);
795 static gboolean free_driver(GNode *node, gpointer data)
797 struct connman_element *element = node->data;
799 DBG("element %p name %s", element, element->name);
801 if (element->driver) {
802 if (element->driver->remove)
803 element->driver->remove(element);
805 connman_element_lock(element);
806 element->driver = NULL;
807 connman_element_unlock(element);
813 static gboolean free_node(GNode *node, gpointer data)
815 struct connman_element *element = node->data;
817 DBG("element %p name %s", element, element->name);
819 if (g_node_depth(node) > 1)
820 g_thread_pool_push(thread_unregister, element, NULL);
825 void __connman_element_cleanup(void)
829 g_thread_pool_free(thread_register, TRUE, TRUE);
830 thread_register = NULL;
832 g_static_rw_lock_writer_lock(&element_lock);
833 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
835 g_static_rw_lock_writer_unlock(&element_lock);
837 g_static_rw_lock_writer_lock(&element_lock);
838 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
840 g_static_rw_lock_writer_unlock(&element_lock);
842 g_thread_pool_free(thread_unregister, FALSE, TRUE);
843 thread_unregister = NULL;
845 g_static_rw_lock_writer_lock(&element_lock);
846 g_node_destroy(element_root);
848 g_static_rw_lock_writer_unlock(&element_lock);
850 dbus_connection_unref(connection);