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_CONNECTION:
71 static const char *subtype2string(enum connman_element_subtype type)
74 case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
76 case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
78 case CONNMAN_ELEMENT_SUBTYPE_WIFI:
80 case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
82 case CONNMAN_ELEMENT_SUBTYPE_MODEM:
84 case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
91 static void append_entry(DBusMessageIter *dict,
92 const char *key, int type, void *val)
94 DBusMessageIter entry, value;
95 const char *signature;
97 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
100 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
103 case DBUS_TYPE_STRING:
104 signature = DBUS_TYPE_STRING_AS_STRING;
106 case DBUS_TYPE_UINT16:
107 signature = DBUS_TYPE_UINT16_AS_STRING;
109 case DBUS_TYPE_UINT32:
110 signature = DBUS_TYPE_UINT32_AS_STRING;
112 case DBUS_TYPE_OBJECT_PATH:
113 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
116 signature = DBUS_TYPE_VARIANT_AS_STRING;
120 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
122 dbus_message_iter_append_basic(&value, type, val);
123 dbus_message_iter_close_container(&entry, &value);
125 dbus_message_iter_close_container(dict, &entry);
128 static void append_property(DBusMessageIter *dict,
129 struct connman_property *property)
131 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
132 append_entry(dict, property->name, property->type,
138 static DBusMessage *get_properties(DBusConnection *conn,
139 DBusMessage *msg, void *data)
141 struct connman_element *element = data;
144 DBusMessageIter array, dict;
147 DBG("conn %p", conn);
149 reply = dbus_message_new_method_return(msg);
153 dbus_message_iter_init_append(reply, &array);
155 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
156 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
157 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
158 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
160 if (element->parent != NULL)
161 append_entry(&dict, "Parent",
162 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
164 str = type2string(element->type);
166 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
167 str = subtype2string(element->subtype);
169 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
171 if (element->priority > 0)
172 append_entry(&dict, "Priority",
173 DBUS_TYPE_UINT16, &element->priority);
175 if (element->ipv4.address != NULL)
176 append_entry(&dict, "IPv4.Address",
177 DBUS_TYPE_STRING, &element->ipv4.address);
178 if (element->ipv4.netmask != NULL)
179 append_entry(&dict, "IPv4.Netmask",
180 DBUS_TYPE_STRING, &element->ipv4.netmask);
181 if (element->ipv4.gateway != NULL)
182 append_entry(&dict, "IPv4.Gateway",
183 DBUS_TYPE_STRING, &element->ipv4.gateway);
185 for (list = element->properties; list; list = list->next) {
186 struct connman_property *property = list->data;
188 append_property(&dict, property);
191 dbus_message_iter_close_container(&array, &dict);
196 static GDBusMethodTable element_methods[] = {
197 { "GetProperties", "", "a{sv}", get_properties },
201 struct append_filter {
202 enum connman_element_type type;
203 DBusMessageIter *iter;
206 static gboolean append_path(GNode *node, gpointer data)
208 struct connman_element *element = node->data;
209 struct append_filter *filter = data;
211 DBG("element %p name %s", element, element->name);
213 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
216 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
217 filter->type != element->type)
220 dbus_message_iter_append_basic(filter->iter,
221 DBUS_TYPE_OBJECT_PATH, &element->path);
226 void __connman_element_list(enum connman_element_type type,
227 DBusMessageIter *iter)
229 struct append_filter filter = { type, iter };
233 g_static_rw_lock_reader_lock(&element_lock);
234 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
235 append_path, &filter);
236 g_static_rw_lock_reader_unlock(&element_lock);
239 static gint compare_priority(gconstpointer a, gconstpointer b)
241 const struct connman_driver *driver1 = a;
242 const struct connman_driver *driver2 = b;
244 return driver2->priority - driver1->priority;
247 int connman_driver_register(struct connman_driver *driver)
249 DBG("driver %p name %s", driver, driver->name);
251 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
257 g_static_rw_lock_writer_lock(&driver_lock);
258 driver_list = g_slist_insert_sorted(driver_list, driver,
260 g_static_rw_lock_writer_unlock(&driver_lock);
262 g_thread_pool_push(driver_thread, driver, NULL);
267 static gboolean remove_driver(GNode *node, gpointer data)
269 struct connman_element *element = node->data;
270 struct connman_driver *driver = data;
272 DBG("element %p name %s", element, element->name);
274 if (element->driver == driver) {
276 driver->remove(element);
277 element->driver = NULL;
283 void connman_driver_unregister(struct connman_driver *driver)
285 DBG("driver %p name %s", driver, driver->name);
287 g_static_rw_lock_reader_lock(&element_lock);
288 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
289 remove_driver, driver);
290 g_static_rw_lock_reader_unlock(&element_lock);
292 g_static_rw_lock_writer_lock(&driver_lock);
293 driver_list = g_slist_remove(driver_list, driver);
294 g_static_rw_lock_writer_unlock(&driver_lock);
297 struct connman_element *connman_element_create(void)
299 struct connman_element *element;
301 element = g_new0(struct connman_element, 1);
303 DBG("element %p", element);
305 element->refcount = 1;
307 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
308 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
309 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
311 element->netdev.index = -1;
316 struct connman_element *connman_element_ref(struct connman_element *element)
318 DBG("element %p name %s refcount %d", element, element->name,
319 g_atomic_int_get(&element->refcount) + 1);
321 g_atomic_int_inc(&element->refcount);
326 void connman_element_unref(struct connman_element *element)
328 DBG("element %p name %s refcount %d", element, element->name,
329 g_atomic_int_get(&element->refcount) - 1);
331 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
334 for (list = element->properties; list; list = list->next) {
335 struct connman_property *property = list->data;
336 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
337 property->type == DBUS_TYPE_STRING)
338 g_free(property->value);
342 g_slist_free(element->properties);
344 g_free(element->ipv4.address);
345 g_free(element->ipv4.netmask);
346 g_free(element->ipv4.gateway);
347 g_free(element->ipv4.network);
348 g_free(element->ipv4.broadcast);
349 g_free(element->ipv4.nameserver);
350 g_free(element->netdev.name);
351 g_free(element->path);
352 g_free(element->name);
357 int connman_element_add_static_property(struct connman_element *element,
358 const char *name, int type, const void *value)
360 struct connman_property *property;
362 DBG("element %p name %s", element, element->name);
364 if (type != DBUS_TYPE_STRING)
367 property = g_try_new0(struct connman_property, 1);
368 if (property == NULL)
371 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
373 property->name = g_strdup(name);
374 property->type = type;
376 DBG("name %s type %d value %p", name, type, value);
379 case DBUS_TYPE_STRING:
380 property->value = g_strdup(*((const char **) value));
384 element->properties = g_slist_append(element->properties, property);
389 int connman_element_set_property(struct connman_element *element,
390 enum connman_property_type type, const void *value)
393 case CONNMAN_PROPERTY_TYPE_INVALID:
395 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
396 g_free(element->ipv4.address);
397 element->ipv4.address = g_strdup(*((const char **) value));
399 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
400 g_free(element->ipv4.netmask);
401 element->ipv4.netmask = g_strdup(*((const char **) value));
403 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
404 g_free(element->ipv4.gateway);
405 element->ipv4.gateway = g_strdup(*((const char **) value));
409 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
410 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
411 DBUS_TYPE_OBJECT_PATH, &element->path,
417 int connman_element_get_value(struct connman_element *element,
418 enum connman_property_type type, void *value)
420 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
424 case CONNMAN_PROPERTY_TYPE_INVALID:
426 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
427 if (element->ipv4.address == NULL)
428 return connman_element_get_value(element->parent,
430 *((char **) value) = element->ipv4.address;
432 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
433 if (element->ipv4.netmask == NULL)
434 return connman_element_get_value(element->parent,
436 *((char **) value) = element->ipv4.netmask;
438 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
439 if (element->ipv4.gateway == NULL)
440 return connman_element_get_value(element->parent,
442 *((char **) value) = element->ipv4.gateway;
449 int connman_element_register(struct connman_element *element,
450 struct connman_element *parent)
453 const gchar *basepath;
455 DBG("element %p name %s parent %p", element, element->name, parent);
457 if (connman_element_ref(element) == NULL)
460 __connman_element_load(element);
462 g_static_rw_lock_writer_lock(&element_lock);
465 node = g_node_find(element_root, G_PRE_ORDER,
466 G_TRAVERSE_ALL, parent);
467 basepath = parent->path;
469 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
470 element->subtype = parent->subtype;
476 if (element->name == NULL) {
477 switch (element->type) {
478 case CONNMAN_ELEMENT_TYPE_IPV4:
479 element->name = g_strdup("ipv4");
481 case CONNMAN_ELEMENT_TYPE_IPV6:
482 element->name = g_strdup("ipv6");
484 case CONNMAN_ELEMENT_TYPE_DHCP:
485 element->name = g_strdup("dhcp");
487 case CONNMAN_ELEMENT_TYPE_BOOTP:
488 element->name = g_strdup("bootp");
490 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
491 element->name = g_strdup("zeroconf");
498 element->path = g_strdup_printf("%s/%s", basepath, element->name);
499 element->parent = parent;
501 DBG("element %p path %s", element, element->path);
503 g_node_append_data(node, element);
505 g_static_rw_lock_writer_unlock(&element_lock);
507 __connman_element_store(element);
509 g_dbus_register_interface(connection, element->path,
510 CONNMAN_ELEMENT_INTERFACE,
511 element_methods, NULL, NULL,
514 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
515 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
516 DBUS_TYPE_OBJECT_PATH, &element->path,
519 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
520 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
521 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
522 DBUS_TYPE_OBJECT_PATH, &element->path,
525 g_thread_pool_push(element_thread, element, NULL);
530 void connman_element_unregister(struct connman_element *element)
534 DBG("element %p name %s", element, element->name);
536 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
537 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
538 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
539 DBUS_TYPE_OBJECT_PATH, &element->path,
542 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
543 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
544 DBUS_TYPE_OBJECT_PATH, &element->path,
547 g_dbus_unregister_interface(connection, element->path,
548 CONNMAN_ELEMENT_INTERFACE);
550 g_static_rw_lock_writer_lock(&element_lock);
552 if (element->driver) {
553 if (element->driver->remove)
554 element->driver->remove(element);
555 element->driver = NULL;
558 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
561 g_node_destroy(node);
564 g_static_rw_lock_writer_unlock(&element_lock);
566 connman_element_unref(element);
569 void connman_element_update(struct connman_element *element)
571 DBG("element %p name %s", element, element->name);
573 g_static_rw_lock_reader_lock(&element_lock);
575 if (element->driver && element->driver->update)
576 element->driver->update(element);
578 g_static_rw_lock_reader_unlock(&element_lock);
580 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
581 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
582 DBUS_TYPE_OBJECT_PATH, &element->path,
586 static inline void set_driver(struct connman_element *element,
587 struct connman_driver *driver)
589 g_static_rw_lock_reader_lock(&element_lock);
590 element->driver = driver;
591 g_static_rw_lock_reader_unlock(&element_lock);
594 static gboolean match_driver(struct connman_element *element,
595 struct connman_driver *driver)
597 if (element->type != driver->type &&
598 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
601 if (element->subtype == driver->subtype ||
602 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
608 static gboolean probe_driver(GNode *node, gpointer data)
610 struct connman_element *element = node->data;
611 struct connman_driver *driver = data;
613 DBG("element %p name %s", element, element->name);
615 if (!element->driver && match_driver(element, driver) == TRUE) {
616 element->driver = driver;
618 if (driver->probe(element) < 0)
619 element->driver = NULL;
625 static void driver_probe(gpointer data, gpointer user_data)
627 struct connman_driver *driver = data;
629 DBG("driver %p name %s", driver, driver->name);
631 g_static_rw_lock_reader_lock(&element_lock);
632 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
633 probe_driver, driver);
634 g_static_rw_lock_reader_unlock(&element_lock);
637 static void element_probe(gpointer data, gpointer user_data)
639 struct connman_element *element = data;
642 DBG("element %p name %s", element, element->name);
644 if (connman_element_ref(element) == NULL)
647 g_static_rw_lock_reader_lock(&driver_lock);
649 for (list = driver_list; list; list = list->next) {
650 struct connman_driver *driver = list->data;
652 DBG("driver %p name %s", driver, driver->name);
654 set_driver(element, driver);
656 if (match_driver(element, driver) == TRUE &&
657 driver->probe(element) == 0)
660 set_driver(element, NULL);
663 g_static_rw_lock_reader_unlock(&driver_lock);
665 connman_element_unref(element);
668 int __connman_element_init(DBusConnection *conn)
670 struct connman_element *element;
672 DBG("conn %p", conn);
674 connection = dbus_connection_ref(conn);
675 if (connection == NULL)
678 g_static_rw_lock_writer_lock(&element_lock);
680 element = connman_element_create();
682 element->name = g_strdup("root");
683 element->path = g_strdup("/");
684 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
686 element_root = g_node_new(element);
688 g_static_rw_lock_writer_unlock(&element_lock);
690 element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
692 driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
697 static gboolean free_node(GNode *node, gpointer data)
699 struct connman_element *element = node->data;
701 DBG("element %p name %s", element, element->name);
703 g_dbus_unregister_interface(connection, element->path,
704 CONNMAN_ELEMENT_INTERFACE);
706 if (element->driver) {
707 if (element->driver->remove)
708 element->driver->remove(element);
709 element->driver = NULL;
712 connman_element_unref(element);
719 void __connman_element_cleanup(void)
723 g_thread_pool_free(driver_thread, TRUE, TRUE);
725 g_thread_pool_free(element_thread, TRUE, TRUE);
727 g_static_rw_lock_writer_lock(&element_lock);
729 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
732 g_node_destroy(element_root);
735 g_static_rw_lock_writer_unlock(&element_lock);
737 dbus_connection_unref(connection);