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 GStaticMutex driver_mutex = G_STATIC_MUTEX_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;
110 signature = DBUS_TYPE_VARIANT_AS_STRING;
114 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
116 dbus_message_iter_append_basic(&value, type, val);
117 dbus_message_iter_close_container(&entry, &value);
119 dbus_message_iter_close_container(dict, &entry);
122 static DBusMessage *get_properties(DBusConnection *conn,
123 DBusMessage *msg, void *data)
125 struct connman_element *element = data;
127 DBusMessageIter array, dict;
130 DBG("conn %p", conn);
132 reply = dbus_message_new_method_return(msg);
136 dbus_message_iter_init_append(reply, &array);
138 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
139 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
140 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
141 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
143 str = type2string(element->type);
145 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
147 str = subtype2string(element->subtype);
149 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
151 if (element->info.driver != NULL)
152 append_entry(&dict, "Driver",
153 DBUS_TYPE_STRING, &element->info.driver);
155 if (element->info.vendor != NULL)
156 append_entry(&dict, "Vendor",
157 DBUS_TYPE_STRING, &element->info.vendor);
159 if (element->info.product != NULL)
160 append_entry(&dict, "Product",
161 DBUS_TYPE_STRING, &element->info.product);
163 if (element->ipv4.address != NULL)
164 append_entry(&dict, "IPv4.Address",
165 DBUS_TYPE_STRING, &element->ipv4.address);
167 if (element->ipv4.netmask != NULL)
168 append_entry(&dict, "IPv4.Netmask",
169 DBUS_TYPE_STRING, &element->ipv4.netmask);
171 if (element->ipv4.gateway != NULL)
172 append_entry(&dict, "IPv4.Gateway",
173 DBUS_TYPE_STRING, &element->ipv4.gateway);
175 dbus_message_iter_close_container(&array, &dict);
180 static GDBusMethodTable element_methods[] = {
181 { "GetProperties", "", "a{sv}", get_properties },
185 struct append_filter {
186 enum connman_element_type type;
187 DBusMessageIter *iter;
190 static gboolean append_path(GNode *node, gpointer data)
192 struct connman_element *element = node->data;
193 struct append_filter *filter = data;
195 DBG("element %p name %s", element, element->name);
197 if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
200 if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
201 filter->type != element->type)
204 dbus_message_iter_append_basic(filter->iter,
205 DBUS_TYPE_OBJECT_PATH, &element->path);
210 void __connman_element_list(enum connman_element_type type,
211 DBusMessageIter *iter)
213 struct append_filter filter = { type, iter };
217 g_static_mutex_lock(&element_mutex);
218 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
219 append_path, &filter);
220 g_static_mutex_unlock(&element_mutex);
223 static gint compare_priority(gconstpointer a, gconstpointer b)
225 const struct connman_driver *driver1 = a;
226 const struct connman_driver *driver2 = b;
228 return driver2->priority - driver1->priority;
231 int connman_driver_register(struct connman_driver *driver)
233 DBG("driver %p name %s", driver, driver->name);
235 if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
241 g_static_mutex_lock(&driver_mutex);
242 driver_list = g_slist_insert_sorted(driver_list, driver,
244 g_static_mutex_unlock(&driver_mutex);
246 g_thread_pool_push(driver_thread, driver, NULL);
251 static gboolean remove_driver(GNode *node, gpointer data)
253 struct connman_element *element = node->data;
254 struct connman_driver *driver = data;
256 DBG("element %p name %s", element, element->name);
258 if (element->driver == driver) {
260 driver->remove(element);
261 element->driver = NULL;
267 void connman_driver_unregister(struct connman_driver *driver)
269 DBG("driver %p name %s", driver, driver->name);
271 g_static_mutex_lock(&element_mutex);
272 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
273 remove_driver, driver);
274 g_static_mutex_unlock(&element_mutex);
276 g_static_mutex_lock(&driver_mutex);
277 driver_list = g_slist_remove(driver_list, driver);
278 g_static_mutex_unlock(&driver_mutex);
281 struct connman_element *connman_element_create(void)
283 struct connman_element *element;
285 element = g_new0(struct connman_element, 1);
287 DBG("element %p", element);
289 element->refcount = 1;
291 element->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
292 element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
293 element->state = CONNMAN_ELEMENT_STATE_CLOSED;
295 element->netdev.index = -1;
300 struct connman_element *connman_element_ref(struct connman_element *element)
302 DBG("element %p name %s refcount %d", element, element->name,
303 g_atomic_int_get(&element->refcount) + 1);
305 g_atomic_int_inc(&element->refcount);
310 void connman_element_unref(struct connman_element *element)
312 DBG("element %p name %s refcount %d", element, element->name,
313 g_atomic_int_get(&element->refcount) - 1);
315 if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
316 g_free(element->ipv4.address);
317 g_free(element->ipv4.netmask);
318 g_free(element->ipv4.gateway);
319 g_free(element->ipv4.network);
320 g_free(element->ipv4.broadcast);
321 g_free(element->ipv4.nameserver);
322 g_free(element->netdev.name);
323 g_free(element->info.driver);
324 g_free(element->info.vendor);
325 g_free(element->info.product);
326 g_free(element->path);
327 g_free(element->name);
332 int connman_element_register(struct connman_element *element,
333 struct connman_element *parent)
336 const gchar *basepath;
338 DBG("element %p name %s parent %p", element, element->name, parent);
340 if (connman_element_ref(element) == NULL)
343 g_static_mutex_lock(&element_mutex);
346 node = g_node_find(element_root, G_PRE_ORDER,
347 G_TRAVERSE_ALL, parent);
348 basepath = parent->path;
350 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
351 element->subtype = parent->subtype;
357 if (element->name == NULL) {
358 switch (element->type) {
359 case CONNMAN_ELEMENT_TYPE_IPV4:
360 element->name = g_strdup("ipv4");
362 case CONNMAN_ELEMENT_TYPE_IPV6:
363 element->name = g_strdup("ipv6");
365 case CONNMAN_ELEMENT_TYPE_DHCP:
366 element->name = g_strdup("dhcp");
368 case CONNMAN_ELEMENT_TYPE_BOOTP:
369 element->name = g_strdup("bootp");
371 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
372 element->name = g_strdup("zeroconf");
379 element->path = g_strdup_printf("%s/%s", basepath, element->name);
380 element->parent = parent;
382 DBG("element %p path %s", element, element->path);
384 g_node_append_data(node, element);
386 g_static_mutex_unlock(&element_mutex);
388 g_dbus_register_interface(connection, element->path,
389 CONNMAN_ELEMENT_INTERFACE,
390 element_methods, NULL, NULL,
393 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
394 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
395 DBUS_TYPE_OBJECT_PATH, &element->path,
398 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
399 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
400 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
401 DBUS_TYPE_OBJECT_PATH, &element->path,
404 g_thread_pool_push(element_thread, element, NULL);
409 void connman_element_unregister(struct connman_element *element)
413 DBG("element %p name %s", element, element->name);
415 if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
416 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
417 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
418 DBUS_TYPE_OBJECT_PATH, &element->path,
421 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
422 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
423 DBUS_TYPE_OBJECT_PATH, &element->path,
426 g_dbus_unregister_interface(connection, element->path,
427 CONNMAN_ELEMENT_INTERFACE);
429 g_static_mutex_lock(&element_mutex);
431 if (element->driver) {
432 if (element->driver->remove)
433 element->driver->remove(element);
434 element->driver = NULL;
437 node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
440 g_node_destroy(node);
443 g_static_mutex_unlock(&element_mutex);
445 connman_element_unref(element);
448 void connman_element_update(struct connman_element *element)
450 DBG("element %p name %s", element, element->name);
452 g_static_mutex_lock(&element_mutex);
454 if (element->driver && element->driver->update)
455 element->driver->update(element);
457 g_static_mutex_unlock(&element_mutex);
460 static inline void set_driver(struct connman_element *element,
461 struct connman_driver *driver)
463 g_static_mutex_lock(&element_mutex);
464 element->driver = driver;
465 g_static_mutex_unlock(&element_mutex);
468 static gboolean match_driver(struct connman_element *element,
469 struct connman_driver *driver)
471 if (element->type != driver->type &&
472 driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
475 if (element->subtype == driver->subtype ||
476 driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
482 static gboolean probe_driver(GNode *node, gpointer data)
484 struct connman_element *element = node->data;
485 struct connman_driver *driver = data;
487 DBG("element %p name %s", element, element->name);
489 if (!element->driver && match_driver(element, driver) == TRUE) {
490 element->driver = driver;
492 if (driver->probe(element) < 0)
493 element->driver = NULL;
499 static void driver_probe(gpointer data, gpointer user_data)
501 struct connman_driver *driver = data;
503 DBG("driver %p name %s", driver, driver->name);
505 g_static_mutex_lock(&element_mutex);
506 g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
507 probe_driver, driver);
508 g_static_mutex_unlock(&element_mutex);
511 static void element_probe(gpointer data, gpointer user_data)
513 struct connman_element *element = data;
516 DBG("element %p name %s", element, element->name);
518 if (connman_element_ref(element) == NULL)
521 g_static_mutex_lock(&driver_mutex);
523 for (list = driver_list; list; list = list->next) {
524 struct connman_driver *driver = list->data;
526 DBG("driver %p name %s", driver, driver->name);
528 set_driver(element, driver);
530 if (match_driver(element, driver) == TRUE &&
531 driver->probe(element) == 0)
534 set_driver(element, NULL);
537 g_static_mutex_unlock(&driver_mutex);
539 connman_element_unref(element);
542 int __connman_element_init(DBusConnection *conn)
544 struct connman_element *element;
546 DBG("conn %p", conn);
548 connection = dbus_connection_ref(conn);
549 if (connection == NULL)
552 g_static_mutex_lock(&element_mutex);
554 element = connman_element_create();
556 element->name = g_strdup("root");
557 element->path = g_strdup("/");
558 element->type = CONNMAN_ELEMENT_TYPE_ROOT;
560 element_root = g_node_new(element);
562 g_static_mutex_unlock(&element_mutex);
564 element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
566 driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
571 static gboolean free_node(GNode *node, gpointer data)
573 struct connman_element *element = node->data;
575 DBG("element %p name %s", element, element->name);
577 g_dbus_unregister_interface(connection, element->path,
578 CONNMAN_ELEMENT_INTERFACE);
580 if (element->driver) {
581 if (element->driver->remove)
582 element->driver->remove(element);
583 element->driver = NULL;
586 connman_element_unref(element);
593 void __connman_element_cleanup(void)
597 g_thread_pool_free(driver_thread, TRUE, TRUE);
599 g_thread_pool_free(element_thread, TRUE, TRUE);
601 g_static_mutex_lock(&element_mutex);
603 g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
606 g_node_destroy(element_root);
609 g_static_mutex_unlock(&element_mutex);
611 dbus_connection_unref(connection);