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 driver_lock = G_STATIC_RW_LOCK_INIT;
36 static GSList *driver_list = NULL;
37 static GThreadPool *driver_thread;
39 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
40 static GNode *element_root = NULL;
41 static GThreadPool *element_thread;
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_CONNECTION:
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_STRING:
106 signature = DBUS_TYPE_STRING_AS_STRING;
108 case DBUS_TYPE_UINT16:
109 signature = DBUS_TYPE_UINT16_AS_STRING;
111 case DBUS_TYPE_UINT32:
112 signature = DBUS_TYPE_UINT32_AS_STRING;
114 case DBUS_TYPE_OBJECT_PATH:
115 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
118 signature = DBUS_TYPE_VARIANT_AS_STRING;
122 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
124 dbus_message_iter_append_basic(&value, type, val);
125 dbus_message_iter_close_container(&entry, &value);
127 dbus_message_iter_close_container(dict, &entry);
130 static void append_property(DBusMessageIter *dict,
131 struct connman_property *property)
133 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
134 append_entry(dict, property->name, property->type,
140 static DBusMessage *get_properties(DBusConnection *conn,
141 DBusMessage *msg, void *data)
143 struct connman_element *element = data;
146 DBusMessageIter array, dict;
149 DBG("conn %p", conn);
151 reply = dbus_message_new_method_return(msg);
155 dbus_message_iter_init_append(reply, &array);
157 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
158 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
159 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
160 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
162 if (element->parent != NULL)
163 append_entry(&dict, "Parent",
164 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
166 str = type2string(element->type);
168 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
169 str = subtype2string(element->subtype);
171 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
173 if (element->priority > 0)
174 append_entry(&dict, "Priority",
175 DBUS_TYPE_UINT16, &element->priority);
177 if (element->ipv4.address != NULL)
178 append_entry(&dict, "IPv4.Address",
179 DBUS_TYPE_STRING, &element->ipv4.address);
180 if (element->ipv4.netmask != NULL)
181 append_entry(&dict, "IPv4.Netmask",
182 DBUS_TYPE_STRING, &element->ipv4.netmask);
183 if (element->ipv4.gateway != NULL)
184 append_entry(&dict, "IPv4.Gateway",
185 DBUS_TYPE_STRING, &element->ipv4.gateway);
187 for (list = element->properties; list; list = list->next) {
188 struct connman_property *property = list->data;
190 append_property(&dict, property);
193 dbus_message_iter_close_container(&array, &dict);
198 static GDBusMethodTable element_methods[] = {
199 { "GetProperties", "", "a{sv}", get_properties },
203 struct append_filter {
204 enum connman_element_type type;
205 DBusMessageIter *iter;
208 static gboolean append_path(GNode *node, gpointer data)
210 struct connman_element *element = node->data;
211 struct append_filter *filter = data;
213 DBG("element %p name %s", element, element->name);
215 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
218 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
219 filter->type != element->type)
222 dbus_message_iter_append_basic(filter->iter,
223 DBUS_TYPE_OBJECT_PATH, &element->path);
228 void __connman_element_list(enum connman_element_type type,
229 DBusMessageIter *iter)
231 struct append_filter filter = { type, iter };
235 g_static_rw_lock_reader_lock(&element_lock);
236 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
237 append_path, &filter);
238 g_static_rw_lock_reader_unlock(&element_lock);
241 static gint compare_priority(gconstpointer a, gconstpointer b)
243 const struct connman_driver *driver1 = a;
244 const struct connman_driver *driver2 = b;
246 return driver2->priority - driver1->priority;
249 int connman_driver_register(struct connman_driver *driver)
251 DBG("driver %p name %s", driver, driver->name);
253 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
259 g_static_rw_lock_writer_lock(&driver_lock);
260 driver_list = g_slist_insert_sorted(driver_list, driver,
262 g_static_rw_lock_writer_unlock(&driver_lock);
264 g_thread_pool_push(driver_thread, driver, NULL);
269 static gboolean remove_driver(GNode *node, gpointer data)
271 struct connman_element *element = node->data;
272 struct connman_driver *driver = data;
274 DBG("element %p name %s", element, element->name);
276 if (element->driver == driver) {
278 driver->remove(element);
279 element->driver = NULL;
285 void connman_driver_unregister(struct connman_driver *driver)
287 DBG("driver %p name %s", driver, driver->name);
289 g_static_rw_lock_reader_lock(&element_lock);
290 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
291 remove_driver, driver);
292 g_static_rw_lock_reader_unlock(&element_lock);
294 g_static_rw_lock_writer_lock(&driver_lock);
295 driver_list = g_slist_remove(driver_list, driver);
296 g_static_rw_lock_writer_unlock(&driver_lock);
299 struct connman_element *connman_element_create(void)
301 struct connman_element *element;
303 element = g_new0(struct connman_element, 1);
305 DBG("element %p", element);
307 element->refcount = 1;
309 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
310 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
311 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
313 element->netdev.index = -1;
318 struct connman_element *connman_element_ref(struct connman_element *element)
320 DBG("element %p name %s refcount %d", element, element->name,
321 g_atomic_int_get(&element->refcount) + 1);
323 g_atomic_int_inc(&element->refcount);
328 void connman_element_unref(struct connman_element *element)
330 DBG("element %p name %s refcount %d", element, element->name,
331 g_atomic_int_get(&element->refcount) - 1);
333 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
336 for (list = element->properties; list; list = list->next) {
337 struct connman_property *property = list->data;
338 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
339 property->type == DBUS_TYPE_STRING)
340 g_free(property->value);
344 g_slist_free(element->properties);
346 g_free(element->ipv4.address);
347 g_free(element->ipv4.netmask);
348 g_free(element->ipv4.gateway);
349 g_free(element->ipv4.network);
350 g_free(element->ipv4.broadcast);
351 g_free(element->ipv4.nameserver);
352 g_free(element->netdev.name);
353 g_free(element->path);
354 g_free(element->name);
359 int connman_element_add_static_property(struct connman_element *element,
360 const char *name, int type, const void *value)
362 struct connman_property *property;
364 DBG("element %p name %s", element, element->name);
366 if (type != DBUS_TYPE_STRING)
369 property = g_try_new0(struct connman_property, 1);
370 if (property == NULL)
373 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
375 property->name = g_strdup(name);
376 property->type = type;
378 DBG("name %s type %d value %p", name, type, value);
381 case DBUS_TYPE_STRING:
382 property->value = g_strdup(*((const char **) value));
386 element->properties = g_slist_append(element->properties, property);
391 int connman_element_set_property(struct connman_element *element,
392 enum connman_property_type type, const void *value)
395 case CONNMAN_PROPERTY_TYPE_INVALID:
397 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
398 g_free(element->ipv4.address);
399 element->ipv4.address = g_strdup(*((const char **) value));
401 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
402 g_free(element->ipv4.netmask);
403 element->ipv4.netmask = g_strdup(*((const char **) value));
405 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
406 g_free(element->ipv4.gateway);
407 element->ipv4.gateway = g_strdup(*((const char **) value));
409 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
410 g_free(element->ipv4.nameserver);
411 element->ipv4.nameserver = g_strdup(*((const char **) value));
415 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
416 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
417 DBUS_TYPE_OBJECT_PATH, &element->path,
423 int connman_element_get_value(struct connman_element *element,
424 enum connman_property_type type, void *value)
426 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
430 case CONNMAN_PROPERTY_TYPE_INVALID:
432 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
433 if (element->ipv4.address == NULL)
434 return connman_element_get_value(element->parent,
436 *((char **) value) = element->ipv4.address;
438 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
439 if (element->ipv4.netmask == NULL)
440 return connman_element_get_value(element->parent,
442 *((char **) value) = element->ipv4.netmask;
444 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
445 if (element->ipv4.gateway == NULL)
446 return connman_element_get_value(element->parent,
448 *((char **) value) = element->ipv4.gateway;
450 case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
451 if (element->ipv4.nameserver == NULL)
452 return connman_element_get_value(element->parent,
454 *((char **) value) = element->ipv4.nameserver;
461 int connman_element_register(struct connman_element *element,
462 struct connman_element *parent)
465 const gchar *basepath;
467 DBG("element %p name %s parent %p", element, element->name, parent);
469 if (connman_element_ref(element) == NULL)
472 __connman_element_load(element);
474 g_static_rw_lock_writer_lock(&element_lock);
477 node = g_node_find(element_root, G_PRE_ORDER,
478 G_TRAVERSE_ALL, parent);
479 basepath = parent->path;
481 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
482 element->subtype = parent->subtype;
488 if (element->name == NULL) {
489 switch (element->type) {
490 case CONNMAN_ELEMENT_TYPE_IPV4:
491 element->name = g_strdup("ipv4");
493 case CONNMAN_ELEMENT_TYPE_IPV6:
494 element->name = g_strdup("ipv6");
496 case CONNMAN_ELEMENT_TYPE_DHCP:
497 element->name = g_strdup("dhcp");
499 case CONNMAN_ELEMENT_TYPE_BOOTP:
500 element->name = g_strdup("bootp");
502 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
503 element->name = g_strdup("zeroconf");
505 case CONNMAN_ELEMENT_TYPE_RESOLVER:
506 element->name = g_strdup("resolver");
513 element->path = g_strdup_printf("%s/%s", basepath, element->name);
514 element->parent = parent;
516 DBG("element %p path %s", element, element->path);
518 g_node_append_data(node, element);
520 g_static_rw_lock_writer_unlock(&element_lock);
522 __connman_element_store(element);
524 g_dbus_register_interface(connection, element->path,
525 CONNMAN_ELEMENT_INTERFACE,
526 element_methods, NULL, NULL,
529 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
530 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
531 DBUS_TYPE_OBJECT_PATH, &element->path,
534 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
535 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
536 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
537 DBUS_TYPE_OBJECT_PATH, &element->path,
540 g_thread_pool_push(element_thread, element, NULL);
545 void connman_element_unregister(struct connman_element *element)
549 DBG("element %p name %s", element, element->name);
551 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
552 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
553 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
554 DBUS_TYPE_OBJECT_PATH, &element->path,
557 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
558 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
559 DBUS_TYPE_OBJECT_PATH, &element->path,
562 g_dbus_unregister_interface(connection, element->path,
563 CONNMAN_ELEMENT_INTERFACE);
565 g_static_rw_lock_writer_lock(&element_lock);
567 if (element->driver) {
568 if (element->driver->remove)
569 element->driver->remove(element);
570 element->driver = NULL;
573 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
576 g_node_destroy(node);
579 g_static_rw_lock_writer_unlock(&element_lock);
581 connman_element_unref(element);
584 void connman_element_update(struct connman_element *element)
586 DBG("element %p name %s", element, element->name);
588 g_static_rw_lock_reader_lock(&element_lock);
590 if (element->driver && element->driver->update)
591 element->driver->update(element);
593 g_static_rw_lock_reader_unlock(&element_lock);
595 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
596 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
597 DBUS_TYPE_OBJECT_PATH, &element->path,
601 static inline void set_driver(struct connman_element *element,
602 struct connman_driver *driver)
604 g_static_rw_lock_reader_lock(&element_lock);
605 element->driver = driver;
606 g_static_rw_lock_reader_unlock(&element_lock);
609 static gboolean match_driver(struct connman_element *element,
610 struct connman_driver *driver)
612 if (element->type != driver->type &&
613 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
616 if (element->subtype == driver->subtype ||
617 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
623 static gboolean probe_driver(GNode *node, gpointer data)
625 struct connman_element *element = node->data;
626 struct connman_driver *driver = data;
628 DBG("element %p name %s", element, element->name);
630 if (!element->driver && match_driver(element, driver) == TRUE) {
631 element->driver = driver;
633 if (driver->probe(element) < 0)
634 element->driver = NULL;
640 static void driver_probe(gpointer data, gpointer user_data)
642 struct connman_driver *driver = data;
644 DBG("driver %p name %s", driver, driver->name);
646 g_static_rw_lock_reader_lock(&element_lock);
647 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
648 probe_driver, driver);
649 g_static_rw_lock_reader_unlock(&element_lock);
652 static void element_probe(gpointer data, gpointer user_data)
654 struct connman_element *element = data;
657 DBG("element %p name %s", element, element->name);
659 if (connman_element_ref(element) == NULL)
662 g_static_rw_lock_reader_lock(&driver_lock);
664 for (list = driver_list; list; list = list->next) {
665 struct connman_driver *driver = list->data;
667 DBG("driver %p name %s", driver, driver->name);
669 set_driver(element, driver);
671 if (match_driver(element, driver) == TRUE &&
672 driver->probe(element) == 0)
675 set_driver(element, NULL);
678 g_static_rw_lock_reader_unlock(&driver_lock);
680 connman_element_unref(element);
683 int __connman_element_init(DBusConnection *conn)
685 struct connman_element *element;
687 DBG("conn %p", conn);
689 connection = dbus_connection_ref(conn);
690 if (connection == NULL)
693 g_static_rw_lock_writer_lock(&element_lock);
695 element = connman_element_create();
697 element->name = g_strdup("root");
698 element->path = g_strdup("/");
699 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
701 element_root = g_node_new(element);
703 g_static_rw_lock_writer_unlock(&element_lock);
705 element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
707 driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
712 static gboolean free_node(GNode *node, gpointer data)
714 struct connman_element *element = node->data;
716 DBG("element %p name %s", element, element->name);
718 g_dbus_unregister_interface(connection, element->path,
719 CONNMAN_ELEMENT_INTERFACE);
721 if (element->driver) {
722 if (element->driver->remove)
723 element->driver->remove(element);
724 element->driver = NULL;
727 connman_element_unref(element);
734 void __connman_element_cleanup(void)
738 g_thread_pool_free(driver_thread, TRUE, TRUE);
740 g_thread_pool_free(element_thread, TRUE, TRUE);
742 g_static_rw_lock_writer_lock(&element_lock);
744 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
747 g_node_destroy(element_root);
750 g_static_rw_lock_writer_unlock(&element_lock);
752 dbus_connection_unref(connection);