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 GStaticMutex element_mutex = G_STATIC_MUTEX_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_OBJECT_PATH:
110 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
113 signature = DBUS_TYPE_VARIANT_AS_STRING;
117 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
119 dbus_message_iter_append_basic(&value, type, val);
120 dbus_message_iter_close_container(&entry, &value);
122 dbus_message_iter_close_container(dict, &entry);
125 static void append_property(DBusMessageIter *dict,
126 struct connman_property *property)
128 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
129 append_entry(dict, property->name, property->type,
135 static DBusMessage *get_properties(DBusConnection *conn,
136 DBusMessage *msg, void *data)
138 struct connman_element *element = data;
141 DBusMessageIter array, dict;
144 DBG("conn %p", conn);
146 reply = dbus_message_new_method_return(msg);
150 dbus_message_iter_init_append(reply, &array);
152 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
153 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
154 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
155 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
157 if (element->parent != NULL)
158 append_entry(&dict, "Parent",
159 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
161 str = type2string(element->type);
163 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
164 str = subtype2string(element->subtype);
166 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
168 if (element->ipv4.address != NULL)
169 append_entry(&dict, "IPv4.Address",
170 DBUS_TYPE_STRING, &element->ipv4.address);
171 if (element->ipv4.netmask != NULL)
172 append_entry(&dict, "IPv4.Netmask",
173 DBUS_TYPE_STRING, &element->ipv4.netmask);
174 if (element->ipv4.gateway != NULL)
175 append_entry(&dict, "IPv4.Gateway",
176 DBUS_TYPE_STRING, &element->ipv4.gateway);
178 for (list = element->properties; list; list = list->next) {
179 struct connman_property *property = list->data;
181 append_property(&dict, property);
184 dbus_message_iter_close_container(&array, &dict);
189 static GDBusMethodTable element_methods[] = {
190 { "GetProperties", "", "a{sv}", get_properties },
194 struct append_filter {
195 enum connman_element_type type;
196 DBusMessageIter *iter;
199 static gboolean append_path(GNode *node, gpointer data)
201 struct connman_element *element = node->data;
202 struct append_filter *filter = data;
204 DBG("element %p name %s", element, element->name);
206 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
209 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
210 filter->type != element->type)
213 dbus_message_iter_append_basic(filter->iter,
214 DBUS_TYPE_OBJECT_PATH, &element->path);
219 void __connman_element_list(enum connman_element_type type,
220 DBusMessageIter *iter)
222 struct append_filter filter = { type, iter };
226 g_static_mutex_lock(&element_mutex);
227 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
228 append_path, &filter);
229 g_static_mutex_unlock(&element_mutex);
232 static gint compare_priority(gconstpointer a, gconstpointer b)
234 const struct connman_driver *driver1 = a;
235 const struct connman_driver *driver2 = b;
237 return driver2->priority - driver1->priority;
240 int connman_driver_register(struct connman_driver *driver)
242 DBG("driver %p name %s", driver, driver->name);
244 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
250 g_static_rw_lock_writer_lock(&driver_lock);
251 driver_list = g_slist_insert_sorted(driver_list, driver,
253 g_static_rw_lock_writer_unlock(&driver_lock);
255 g_thread_pool_push(driver_thread, driver, NULL);
260 static gboolean remove_driver(GNode *node, gpointer data)
262 struct connman_element *element = node->data;
263 struct connman_driver *driver = data;
265 DBG("element %p name %s", element, element->name);
267 if (element->driver == driver) {
269 driver->remove(element);
270 element->driver = NULL;
276 void connman_driver_unregister(struct connman_driver *driver)
278 DBG("driver %p name %s", driver, driver->name);
280 g_static_mutex_lock(&element_mutex);
281 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
282 remove_driver, driver);
283 g_static_mutex_unlock(&element_mutex);
285 g_static_rw_lock_writer_lock(&driver_lock);
286 driver_list = g_slist_remove(driver_list, driver);
287 g_static_rw_lock_writer_unlock(&driver_lock);
290 struct connman_element *connman_element_create(void)
292 struct connman_element *element;
294 element = g_new0(struct connman_element, 1);
296 DBG("element %p", element);
298 element->refcount = 1;
300 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
301 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
302 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
304 element->netdev.index = -1;
309 struct connman_element *connman_element_ref(struct connman_element *element)
311 DBG("element %p name %s refcount %d", element, element->name,
312 g_atomic_int_get(&element->refcount) + 1);
314 g_atomic_int_inc(&element->refcount);
319 void connman_element_unref(struct connman_element *element)
321 DBG("element %p name %s refcount %d", element, element->name,
322 g_atomic_int_get(&element->refcount) - 1);
324 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
327 for (list = element->properties; list; list = list->next) {
328 struct connman_property *property = list->data;
329 if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
330 property->type == DBUS_TYPE_STRING)
331 g_free(property->value);
335 g_slist_free(element->properties);
337 g_free(element->ipv4.address);
338 g_free(element->ipv4.netmask);
339 g_free(element->ipv4.gateway);
340 g_free(element->ipv4.network);
341 g_free(element->ipv4.broadcast);
342 g_free(element->ipv4.nameserver);
343 g_free(element->netdev.name);
344 g_free(element->path);
345 g_free(element->name);
350 int connman_element_add_static_property(struct connman_element *element,
351 const char *name, int type, const void *value)
353 struct connman_property *property;
355 DBG("element %p name %s", element, element->name);
357 if (type != DBUS_TYPE_STRING)
360 property = g_try_new0(struct connman_property, 1);
361 if (property == NULL)
364 property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
366 property->name = g_strdup(name);
367 property->type = type;
369 DBG("name %s type %d value %p", name, type, value);
372 case DBUS_TYPE_STRING:
373 property->value = g_strdup(*((const char **) value));
377 element->properties = g_slist_append(element->properties, property);
382 int connman_element_set_property(struct connman_element *element,
383 enum connman_property_type type, const void *value)
386 case CONNMAN_PROPERTY_TYPE_INVALID:
388 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
389 g_free(element->ipv4.address);
390 element->ipv4.address = g_strdup(*((const char **) value));
392 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
393 g_free(element->ipv4.netmask);
394 element->ipv4.netmask = g_strdup(*((const char **) value));
396 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
397 g_free(element->ipv4.gateway);
398 element->ipv4.gateway = g_strdup(*((const char **) value));
402 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
403 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
404 DBUS_TYPE_OBJECT_PATH, &element->path,
410 int connman_element_get_value(struct connman_element *element,
411 enum connman_property_type type, void *value)
413 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
417 case CONNMAN_PROPERTY_TYPE_INVALID:
419 case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
420 if (element->ipv4.address == NULL)
421 return connman_element_get_value(element->parent,
423 *((char **) value) = element->ipv4.address;
425 case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
426 if (element->ipv4.netmask == NULL)
427 return connman_element_get_value(element->parent,
429 *((char **) value) = element->ipv4.netmask;
431 case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
432 if (element->ipv4.gateway == NULL)
433 return connman_element_get_value(element->parent,
435 *((char **) value) = element->ipv4.gateway;
442 int connman_element_register(struct connman_element *element,
443 struct connman_element *parent)
446 const gchar *basepath;
448 DBG("element %p name %s parent %p", element, element->name, parent);
450 if (connman_element_ref(element) == NULL)
453 g_static_mutex_lock(&element_mutex);
456 node = g_node_find(element_root, G_PRE_ORDER,
457 G_TRAVERSE_ALL, parent);
458 basepath = parent->path;
460 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
461 element->subtype = parent->subtype;
467 if (element->name == NULL) {
468 switch (element->type) {
469 case CONNMAN_ELEMENT_TYPE_IPV4:
470 element->name = g_strdup("ipv4");
472 case CONNMAN_ELEMENT_TYPE_IPV6:
473 element->name = g_strdup("ipv6");
475 case CONNMAN_ELEMENT_TYPE_DHCP:
476 element->name = g_strdup("dhcp");
478 case CONNMAN_ELEMENT_TYPE_BOOTP:
479 element->name = g_strdup("bootp");
481 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
482 element->name = g_strdup("zeroconf");
489 element->path = g_strdup_printf("%s/%s", basepath, element->name);
490 element->parent = parent;
492 DBG("element %p path %s", element, element->path);
494 g_node_append_data(node, element);
496 g_static_mutex_unlock(&element_mutex);
498 g_dbus_register_interface(connection, element->path,
499 CONNMAN_ELEMENT_INTERFACE,
500 element_methods, NULL, NULL,
503 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
504 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
505 DBUS_TYPE_OBJECT_PATH, &element->path,
508 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
509 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
510 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
511 DBUS_TYPE_OBJECT_PATH, &element->path,
514 g_thread_pool_push(element_thread, element, NULL);
519 void connman_element_unregister(struct connman_element *element)
523 DBG("element %p name %s", element, element->name);
525 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
526 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
527 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
528 DBUS_TYPE_OBJECT_PATH, &element->path,
531 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
532 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
533 DBUS_TYPE_OBJECT_PATH, &element->path,
536 g_dbus_unregister_interface(connection, element->path,
537 CONNMAN_ELEMENT_INTERFACE);
539 g_static_mutex_lock(&element_mutex);
541 if (element->driver) {
542 if (element->driver->remove)
543 element->driver->remove(element);
544 element->driver = NULL;
547 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
550 g_node_destroy(node);
553 g_static_mutex_unlock(&element_mutex);
555 connman_element_unref(element);
558 void connman_element_update(struct connman_element *element)
560 DBG("element %p name %s", element, element->name);
562 g_static_mutex_lock(&element_mutex);
564 if (element->driver && element->driver->update)
565 element->driver->update(element);
567 g_static_mutex_unlock(&element_mutex);
569 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
570 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
571 DBUS_TYPE_OBJECT_PATH, &element->path,
575 static inline void set_driver(struct connman_element *element,
576 struct connman_driver *driver)
578 g_static_mutex_lock(&element_mutex);
579 element->driver = driver;
580 g_static_mutex_unlock(&element_mutex);
583 static gboolean match_driver(struct connman_element *element,
584 struct connman_driver *driver)
586 if (element->type != driver->type &&
587 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
590 if (element->subtype == driver->subtype ||
591 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
597 static gboolean probe_driver(GNode *node, gpointer data)
599 struct connman_element *element = node->data;
600 struct connman_driver *driver = data;
602 DBG("element %p name %s", element, element->name);
604 if (!element->driver && match_driver(element, driver) == TRUE) {
605 element->driver = driver;
607 if (driver->probe(element) < 0)
608 element->driver = NULL;
614 static void driver_probe(gpointer data, gpointer user_data)
616 struct connman_driver *driver = data;
618 DBG("driver %p name %s", driver, driver->name);
620 g_static_mutex_lock(&element_mutex);
621 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
622 probe_driver, driver);
623 g_static_mutex_unlock(&element_mutex);
626 static void element_probe(gpointer data, gpointer user_data)
628 struct connman_element *element = data;
631 DBG("element %p name %s", element, element->name);
633 if (connman_element_ref(element) == NULL)
636 g_static_rw_lock_reader_lock(&driver_lock);
638 for (list = driver_list; list; list = list->next) {
639 struct connman_driver *driver = list->data;
641 DBG("driver %p name %s", driver, driver->name);
643 set_driver(element, driver);
645 if (match_driver(element, driver) == TRUE &&
646 driver->probe(element) == 0)
649 set_driver(element, NULL);
652 g_static_rw_lock_reader_unlock(&driver_lock);
654 connman_element_unref(element);
657 int __connman_element_init(DBusConnection *conn)
659 struct connman_element *element;
661 DBG("conn %p", conn);
663 connection = dbus_connection_ref(conn);
664 if (connection == NULL)
667 g_static_mutex_lock(&element_mutex);
669 element = connman_element_create();
671 element->name = g_strdup("root");
672 element->path = g_strdup("/");
673 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
675 element_root = g_node_new(element);
677 g_static_mutex_unlock(&element_mutex);
679 element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
681 driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
686 static gboolean free_node(GNode *node, gpointer data)
688 struct connman_element *element = node->data;
690 DBG("element %p name %s", element, element->name);
692 g_dbus_unregister_interface(connection, element->path,
693 CONNMAN_ELEMENT_INTERFACE);
695 if (element->driver) {
696 if (element->driver->remove)
697 element->driver->remove(element);
698 element->driver = NULL;
701 connman_element_unref(element);
708 void __connman_element_cleanup(void)
712 g_thread_pool_free(driver_thread, TRUE, TRUE);
714 g_thread_pool_free(element_thread, TRUE, TRUE);
716 g_static_mutex_lock(&element_mutex);
718 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
721 g_node_destroy(element_root);
724 g_static_mutex_unlock(&element_mutex);
726 dbus_connection_unref(connection);