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 g_static_rw_lock_writer_lock(&element_lock);
463 node = g_node_find(element_root, G_PRE_ORDER,
464 G_TRAVERSE_ALL, parent);
465 basepath = parent->path;
467 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
468 element->subtype = parent->subtype;
474 if (element->name == NULL) {
475 switch (element->type) {
476 case CONNMAN_ELEMENT_TYPE_IPV4:
477 element->name = g_strdup("ipv4");
479 case CONNMAN_ELEMENT_TYPE_IPV6:
480 element->name = g_strdup("ipv6");
482 case CONNMAN_ELEMENT_TYPE_DHCP:
483 element->name = g_strdup("dhcp");
485 case CONNMAN_ELEMENT_TYPE_BOOTP:
486 element->name = g_strdup("bootp");
488 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
489 element->name = g_strdup("zeroconf");
496 element->path = g_strdup_printf("%s/%s", basepath, element->name);
497 element->parent = parent;
499 DBG("element %p path %s", element, element->path);
501 g_node_append_data(node, element);
503 g_static_rw_lock_writer_unlock(&element_lock);
505 g_dbus_register_interface(connection, element->path,
506 CONNMAN_ELEMENT_INTERFACE,
507 element_methods, NULL, NULL,
510 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
511 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
512 DBUS_TYPE_OBJECT_PATH, &element->path,
515 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
516 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
517 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
518 DBUS_TYPE_OBJECT_PATH, &element->path,
521 g_thread_pool_push(element_thread, element, NULL);
526 void connman_element_unregister(struct connman_element *element)
530 DBG("element %p name %s", element, element->name);
532 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
533 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
534 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
535 DBUS_TYPE_OBJECT_PATH, &element->path,
538 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
539 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
540 DBUS_TYPE_OBJECT_PATH, &element->path,
543 g_dbus_unregister_interface(connection, element->path,
544 CONNMAN_ELEMENT_INTERFACE);
546 g_static_rw_lock_writer_lock(&element_lock);
548 if (element->driver) {
549 if (element->driver->remove)
550 element->driver->remove(element);
551 element->driver = NULL;
554 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
557 g_node_destroy(node);
560 g_static_rw_lock_writer_unlock(&element_lock);
562 connman_element_unref(element);
565 void connman_element_update(struct connman_element *element)
567 DBG("element %p name %s", element, element->name);
569 g_static_rw_lock_reader_lock(&element_lock);
571 if (element->driver && element->driver->update)
572 element->driver->update(element);
574 g_static_rw_lock_reader_unlock(&element_lock);
576 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
577 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
578 DBUS_TYPE_OBJECT_PATH, &element->path,
582 static inline void set_driver(struct connman_element *element,
583 struct connman_driver *driver)
585 g_static_rw_lock_reader_lock(&element_lock);
586 element->driver = driver;
587 g_static_rw_lock_reader_unlock(&element_lock);
590 static gboolean match_driver(struct connman_element *element,
591 struct connman_driver *driver)
593 if (element->type != driver->type &&
594 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
597 if (element->subtype == driver->subtype ||
598 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
604 static gboolean probe_driver(GNode *node, gpointer data)
606 struct connman_element *element = node->data;
607 struct connman_driver *driver = data;
609 DBG("element %p name %s", element, element->name);
611 if (!element->driver && match_driver(element, driver) == TRUE) {
612 element->driver = driver;
614 if (driver->probe(element) < 0)
615 element->driver = NULL;
621 static void driver_probe(gpointer data, gpointer user_data)
623 struct connman_driver *driver = data;
625 DBG("driver %p name %s", driver, driver->name);
627 g_static_rw_lock_reader_lock(&element_lock);
628 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
629 probe_driver, driver);
630 g_static_rw_lock_reader_unlock(&element_lock);
633 static void element_probe(gpointer data, gpointer user_data)
635 struct connman_element *element = data;
638 DBG("element %p name %s", element, element->name);
640 if (connman_element_ref(element) == NULL)
643 g_static_rw_lock_reader_lock(&driver_lock);
645 for (list = driver_list; list; list = list->next) {
646 struct connman_driver *driver = list->data;
648 DBG("driver %p name %s", driver, driver->name);
650 set_driver(element, driver);
652 if (match_driver(element, driver) == TRUE &&
653 driver->probe(element) == 0)
656 set_driver(element, NULL);
659 g_static_rw_lock_reader_unlock(&driver_lock);
661 connman_element_unref(element);
664 int __connman_element_init(DBusConnection *conn)
666 struct connman_element *element;
668 DBG("conn %p", conn);
670 connection = dbus_connection_ref(conn);
671 if (connection == NULL)
674 g_static_rw_lock_writer_lock(&element_lock);
676 element = connman_element_create();
678 element->name = g_strdup("root");
679 element->path = g_strdup("/");
680 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
682 element_root = g_node_new(element);
684 g_static_rw_lock_writer_unlock(&element_lock);
686 element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
688 driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
693 static gboolean free_node(GNode *node, gpointer data)
695 struct connman_element *element = node->data;
697 DBG("element %p name %s", element, element->name);
699 g_dbus_unregister_interface(connection, element->path,
700 CONNMAN_ELEMENT_INTERFACE);
702 if (element->driver) {
703 if (element->driver->remove)
704 element->driver->remove(element);
705 element->driver = NULL;
708 connman_element_unref(element);
715 void __connman_element_cleanup(void)
719 g_thread_pool_free(driver_thread, TRUE, TRUE);
721 g_thread_pool_free(element_thread, TRUE, TRUE);
723 g_static_rw_lock_writer_lock(&element_lock);
725 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
728 g_node_destroy(element_root);
731 g_static_rw_lock_writer_unlock(&element_lock);
733 dbus_connection_unref(connection);