Add documentation for the drivers
[connman] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27
28 #include <glib.h>
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection;
34
35 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
36 static GNode *element_root = NULL;
37
38 static GSList *driver_list = NULL;
39
40 static GThreadPool *thread_register = NULL;
41 static GThreadPool *thread_unregister = NULL;
42 static GThreadPool *thread_unregister_children = NULL;
43
44 static gchar *device_filter = NULL;
45
46 static const char *type2string(enum connman_element_type type)
47 {
48         switch (type) {
49         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
50                 return "unknown";
51         case CONNMAN_ELEMENT_TYPE_ROOT:
52                 return "root";
53         case CONNMAN_ELEMENT_TYPE_DEVICE:
54                 return "device";
55         case CONNMAN_ELEMENT_TYPE_NETWORK:
56                 return "network";
57         case CONNMAN_ELEMENT_TYPE_IPV4:
58                 return "ipv4";
59         case CONNMAN_ELEMENT_TYPE_IPV6:
60                 return "ipv6";
61         case CONNMAN_ELEMENT_TYPE_DHCP:
62                 return "dhcp";
63         case CONNMAN_ELEMENT_TYPE_BOOTP:
64                 return "bootp";
65         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
66                 return "zeroconf";
67         case CONNMAN_ELEMENT_TYPE_RESOLVER:
68                 return "resolver";
69         case CONNMAN_ELEMENT_TYPE_INTERNET:
70                 return "internet";
71         }
72
73         return NULL;
74 }
75
76 static const char *subtype2string(enum connman_element_subtype type)
77 {
78         switch (type) {
79         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
80                 return "unknown";
81         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
82                 return "ethernet";
83         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
84                 return "wifi";
85         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
86                 return "wimax";
87         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
88                 return "modem";
89         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
90                 return "bluetooth";
91         }
92
93         return NULL;
94 }
95
96 static void append_entry(DBusMessageIter *dict,
97                                 const char *key, int type, void *val)
98 {
99         DBusMessageIter entry, value;
100         const char *signature;
101
102         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
103                                                                 NULL, &entry);
104
105         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
106
107         switch (type) {
108         case DBUS_TYPE_BOOLEAN:
109                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
110                 break;
111         case DBUS_TYPE_STRING:
112                 signature = DBUS_TYPE_STRING_AS_STRING;
113                 break;
114         case DBUS_TYPE_UINT16:
115                 signature = DBUS_TYPE_UINT16_AS_STRING;
116                 break;
117         case DBUS_TYPE_UINT32:
118                 signature = DBUS_TYPE_UINT32_AS_STRING;
119                 break;
120         case DBUS_TYPE_OBJECT_PATH:
121                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
122                 break;
123         default:
124                 signature = DBUS_TYPE_VARIANT_AS_STRING;
125                 break;
126         }
127
128         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
129                                                         signature, &value);
130         dbus_message_iter_append_basic(&value, type, val);
131         dbus_message_iter_close_container(&entry, &value);
132
133         dbus_message_iter_close_container(dict, &entry);
134 }
135
136 static void append_property(DBusMessageIter *dict,
137                                 struct connman_property *property)
138 {
139         if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
140                 append_entry(dict, property->name, property->type,
141                                                         &property->value);
142                 return;
143         }
144 }
145
146 static DBusMessage *get_properties(DBusConnection *conn,
147                                         DBusMessage *msg, void *data)
148 {
149         struct connman_element *element = data;
150         GSList *list;
151         DBusMessage *reply;
152         DBusMessageIter array, dict;
153         const char *str;
154
155         DBG("conn %p", conn);
156
157         reply = dbus_message_new_method_return(msg);
158         if (reply == NULL)
159                 return NULL;
160
161         dbus_message_iter_init_append(reply, &array);
162
163         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
164                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
165                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
166                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
167
168         if (element->parent != NULL)
169                 append_entry(&dict, "Parent",
170                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
171
172         str = type2string(element->type);
173         if (str != NULL)
174                 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
175         str = subtype2string(element->subtype);
176         if (str != NULL)
177                 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
178
179         append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &element->enabled);
180
181         if (element->priority > 0)
182                 append_entry(&dict, "Priority",
183                                 DBUS_TYPE_UINT16, &element->priority);
184
185         if (element->network.identifier != NULL)
186                 append_entry(&dict, "Identifier",
187                                 DBUS_TYPE_STRING, &element->network.identifier);
188
189         if (element->ipv4.address != NULL)
190                 append_entry(&dict, "IPv4.Address",
191                                 DBUS_TYPE_STRING, &element->ipv4.address);
192         if (element->ipv4.netmask != NULL)
193                 append_entry(&dict, "IPv4.Netmask",
194                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
195         if (element->ipv4.gateway != NULL)
196                 append_entry(&dict, "IPv4.Gateway",
197                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
198
199         for (list = element->properties; list; list = list->next) {
200                 struct connman_property *property = list->data;
201
202                 append_property(&dict, property);
203         }
204
205         dbus_message_iter_close_container(&array, &dict);
206
207         return reply;
208 }
209
210 static DBusMessage *set_property(DBusConnection *conn,
211                                         DBusMessage *msg, void *data)
212 {
213         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
214 }
215
216 static DBusMessage *do_update(DBusConnection *conn,
217                                         DBusMessage *msg, void *data)
218 {
219         struct connman_element *element = data;
220
221         DBG("conn %p", conn);
222
223         if (element->driver == NULL)
224                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
225
226         if (element->driver->update) {
227                 DBG("Calling update callback");
228                 element->driver->update(element);
229         }
230
231         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
232 }
233
234 static DBusMessage *do_enable(DBusConnection *conn,
235                                         DBusMessage *msg, void *data)
236 {
237         struct connman_element *element = data;
238
239         DBG("conn %p", conn);
240
241         if (element->driver == NULL)
242                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
243
244         if (element->driver->enable) {
245                 DBG("Calling enable callback");
246                 element->driver->enable(element);
247         }
248
249         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
250 }
251
252 static DBusMessage *do_disable(DBusConnection *conn,
253                                         DBusMessage *msg, void *data)
254 {
255         struct connman_element *element = data;
256
257         DBG("conn %p", conn);
258
259         if (element->driver == NULL)
260                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
261
262         if (element->driver->disable) {
263                 DBG("Calling disable callback");
264                 element->driver->disable(element);
265         }
266
267         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
268 }
269
270 static GDBusMethodTable element_methods[] = {
271         { "GetProperties", "",   "a{sv}", get_properties },
272         { "SetProperty",   "sv", "",      set_property   },
273         { "Update",        "",   "",      do_update      },
274         { "Enable",        "",   "",      do_enable      },
275         { "Disable",       "",   "",      do_disable     },
276         { },
277 };
278
279 static GDBusSignalTable element_signals[] = {
280         { "PropertyChanged", "sv" },
281         { },
282 };
283
284 struct append_filter {
285         enum connman_element_type type;
286         DBusMessageIter *iter;
287 };
288
289 static gboolean append_path(GNode *node, gpointer data)
290 {
291         struct connman_element *element = node->data;
292         struct append_filter *filter = data;
293
294         DBG("element %p name %s", element, element->name);
295
296         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
297                 return FALSE;
298
299         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
300                                         filter->type != element->type)
301                 return FALSE;
302
303         dbus_message_iter_append_basic(filter->iter,
304                                 DBUS_TYPE_OBJECT_PATH, &element->path);
305
306         return FALSE;
307 }
308
309 void __connman_element_list(enum connman_element_type type,
310                                                 DBusMessageIter *iter)
311 {
312         struct append_filter filter = { type, iter };
313
314         DBG("");
315
316         g_static_rw_lock_reader_lock(&element_lock);
317         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
318                                                         append_path, &filter);
319         g_static_rw_lock_reader_unlock(&element_lock);
320 }
321
322 static gint compare_priority(gconstpointer a, gconstpointer b)
323 {
324         const struct connman_driver *driver1 = a;
325         const struct connman_driver *driver2 = b;
326
327         return driver2->priority - driver1->priority;
328 }
329
330 static gboolean match_driver(struct connman_element *element,
331                                         struct connman_driver *driver)
332 {
333         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
334                 return FALSE;
335
336         if (element->type != driver->type &&
337                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
338                 return FALSE;
339
340         if (element->subtype == driver->subtype ||
341                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
342                 return TRUE;
343
344         return FALSE;
345 }
346
347 static gboolean probe_driver(GNode *node, gpointer data)
348 {
349         struct connman_element *element = node->data;
350         struct connman_driver *driver = data;
351
352         DBG("element %p name %s", element, element->name);
353
354         if (!element->driver && match_driver(element, driver) == TRUE) {
355                 if (driver->probe(element) < 0)
356                         return FALSE;
357
358                 connman_element_lock(element);
359                 element->driver = driver;
360                 connman_element_unlock(element);
361         }
362
363         return FALSE;
364 }
365
366 /**
367  * connman_driver_register:
368  * @driver: driver definition
369  *
370  * Register a new driver
371  *
372  * Returns: %0 on success
373  */
374 int connman_driver_register(struct connman_driver *driver)
375 {
376         DBG("driver %p name %s", driver, driver->name);
377
378         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
379                 return -EINVAL;
380
381         if (!driver->probe)
382                 return -EINVAL;
383
384         g_static_rw_lock_writer_lock(&element_lock);
385
386         driver_list = g_slist_insert_sorted(driver_list, driver,
387                                                         compare_priority);
388
389         if (element_root != NULL)
390                 g_node_traverse(element_root, G_PRE_ORDER,
391                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
392
393         g_static_rw_lock_writer_unlock(&element_lock);
394
395         return 0;
396 }
397
398 static gboolean remove_driver(GNode *node, gpointer data)
399 {
400         struct connman_element *element = node->data;
401         struct connman_driver *driver = data;
402
403         DBG("element %p name %s", element, element->name);
404
405         if (element->driver == driver) {
406                 if (driver->remove)
407                         driver->remove(element);
408
409                 connman_element_lock(element);
410                 element->driver = NULL;
411                 connman_element_unlock(element);
412         }
413
414         return FALSE;
415 }
416
417 /**
418  * connman_driver_unregister:
419  * @driver: driver definition
420  *
421  * Remove a previously registered driver
422  */
423 void connman_driver_unregister(struct connman_driver *driver)
424 {
425         DBG("driver %p name %s", driver, driver->name);
426
427         g_static_rw_lock_writer_lock(&element_lock);
428
429         driver_list = g_slist_remove(driver_list, driver);
430
431         if (element_root != NULL)
432                 g_node_traverse(element_root, G_POST_ORDER,
433                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
434
435         g_static_rw_lock_writer_unlock(&element_lock);
436 }
437
438 struct connman_element *connman_element_create(void)
439 {
440         struct connman_element *element;
441
442         element = g_new0(struct connman_element, 1);
443
444         DBG("element %p", element);
445
446         element->refcount = 1;
447
448         g_static_mutex_init(&element->mutex);
449
450         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
451         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
452         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
453
454         element->enabled = FALSE;
455
456         element->netdev.index = -1;
457
458         return element;
459 }
460
461 struct connman_element *connman_element_ref(struct connman_element *element)
462 {
463         DBG("element %p name %s refcount %d", element, element->name,
464                                 g_atomic_int_get(&element->refcount) + 1);
465
466         g_atomic_int_inc(&element->refcount);
467
468         return element;
469 }
470
471 void connman_element_unref(struct connman_element *element)
472 {
473         DBG("element %p name %s refcount %d", element, element->name,
474                                 g_atomic_int_get(&element->refcount) - 1);
475
476         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
477                 GSList *list;
478
479                 for (list = element->properties; list; list = list->next) {
480                         struct connman_property *property = list->data;
481                         if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
482                                         property->type == DBUS_TYPE_STRING)
483                                 g_free(property->value);
484                         g_free(property);
485                         list->data = NULL;
486                 }
487                 g_slist_free(element->properties);
488
489                 g_free(element->ipv4.address);
490                 g_free(element->ipv4.netmask);
491                 g_free(element->ipv4.gateway);
492                 g_free(element->ipv4.network);
493                 g_free(element->ipv4.broadcast);
494                 g_free(element->ipv4.nameserver);
495                 g_free(element->network.identifier);
496                 g_free(element->netdev.name);
497                 g_free(element->path);
498                 g_free(element->name);
499                 g_free(element);
500         }
501 }
502
503 int connman_element_add_static_property(struct connman_element *element,
504                                 const char *name, int type, const void *value)
505 {
506         struct connman_property *property;
507
508         DBG("element %p name %s", element, element->name);
509
510         if (type != DBUS_TYPE_STRING)
511                 return -EINVAL;
512
513         property = g_try_new0(struct connman_property, 1);
514         if (property == NULL)
515                 return -ENOMEM;
516
517         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
518
519         property->name = g_strdup(name);
520         property->type = type;
521
522         DBG("name %s type %d value %p", name, type, value);
523
524         switch (type) {
525         case DBUS_TYPE_STRING:
526                 property->value = g_strdup(*((const char **) value));
527                 break;
528         }
529
530         connman_element_lock(element);
531         element->properties = g_slist_append(element->properties, property);
532         connman_element_unlock(element);
533
534         return 0;
535 }
536
537 int connman_element_set_property(struct connman_element *element,
538                         enum connman_property_type type, const void *value)
539 {
540         switch (type) {
541         case CONNMAN_PROPERTY_TYPE_INVALID:
542                 return -EINVAL;
543         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
544                 connman_element_lock(element);
545                 g_free(element->ipv4.address);
546                 element->ipv4.address = g_strdup(*((const char **) value));
547                 connman_element_unlock(element);
548                 break;
549         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
550                 connman_element_lock(element);
551                 g_free(element->ipv4.netmask);
552                 element->ipv4.netmask = g_strdup(*((const char **) value));
553                 connman_element_unlock(element);
554                 break;
555         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
556                 connman_element_lock(element);
557                 g_free(element->ipv4.gateway);
558                 element->ipv4.gateway = g_strdup(*((const char **) value));
559                 connman_element_unlock(element);
560                 break;
561         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
562                 connman_element_lock(element);
563                 g_free(element->ipv4.nameserver);
564                 element->ipv4.nameserver = g_strdup(*((const char **) value));
565                 connman_element_unlock(element);
566                 break;
567         }
568
569         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
570                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
571                                 DBUS_TYPE_OBJECT_PATH, &element->path,
572                                                         DBUS_TYPE_INVALID);
573
574         return 0;
575 }
576
577 int connman_element_get_value(struct connman_element *element,
578                                 enum connman_property_type type, void *value)
579 {
580         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
581                 return -EINVAL;
582
583         switch (type) {
584         case CONNMAN_PROPERTY_TYPE_INVALID:
585                 return -EINVAL;
586         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
587                 if (element->ipv4.address == NULL)
588                         return connman_element_get_value(element->parent,
589                                                                 type, value);
590                 connman_element_lock(element);
591                 *((char **) value) = element->ipv4.address;
592                 connman_element_unlock(element);
593                 break;
594         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
595                 if (element->ipv4.netmask == NULL)
596                         return connman_element_get_value(element->parent,
597                                                                 type, value);
598                 connman_element_lock(element);
599                 *((char **) value) = element->ipv4.netmask;
600                 connman_element_unlock(element);
601                 break;
602         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
603                 if (element->ipv4.gateway == NULL)
604                         return connman_element_get_value(element->parent,
605                                                                 type, value);
606                 connman_element_lock(element);
607                 *((char **) value) = element->ipv4.gateway;
608                 connman_element_unlock(element);
609                 break;
610         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
611                 if (element->ipv4.nameserver == NULL)
612                         return connman_element_get_value(element->parent,
613                                                                 type, value);
614                 connman_element_lock(element);
615                 *((char **) value) = element->ipv4.nameserver;
616                 connman_element_unlock(element);
617                 break;
618         }
619
620         return 0;
621 }
622
623 int connman_element_register(struct connman_element *element,
624                                         struct connman_element *parent)
625 {
626         DBG("element %p name %s parent %p", element, element->name, parent);
627
628         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
629                 if (g_str_equal(device_filter, element->netdev.name) == FALSE)
630                         return -EINVAL;
631         }
632
633         if (connman_element_ref(element) == NULL)
634                 return -EINVAL;
635
636         connman_element_lock(element);
637
638         __connman_element_load(element);
639
640         if (element->name == NULL) {
641                 element->name = g_strdup(type2string(element->type));
642                 if (element->name == NULL)
643                         return -EINVAL;
644         }
645
646         element->parent = parent;
647
648         connman_element_unlock(element);
649
650         if (thread_register != NULL)
651                 g_thread_pool_push(thread_register, element, NULL);
652
653         return 0;
654 }
655
656 void connman_element_unregister(struct connman_element *element)
657 {
658         DBG("element %p name %s", element, element->name);
659
660         if (thread_unregister != NULL)
661                 g_thread_pool_push(thread_unregister, element, NULL);
662 }
663
664 void connman_element_unregister_children(struct connman_element *element)
665 {
666         DBG("element %p name %s", element, element->name);
667
668         if (thread_unregister_children != NULL)
669                 g_thread_pool_push(thread_unregister_children, element, NULL);
670 }
671
672 static gboolean update_element(GNode *node, gpointer user_data)
673 {
674         struct connman_element *element = node->data;
675
676         DBG("element %p name %s", element, element->name);
677
678         if (element->driver && element->driver->update)
679                 element->driver->update(element);
680
681         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
682                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
683                                 DBUS_TYPE_OBJECT_PATH, &element->path,
684                                                         DBUS_TYPE_INVALID);
685
686         return FALSE;
687 }
688
689 void connman_element_update(struct connman_element *element)
690 {
691         GNode *node;
692
693         DBG("element %p name %s", element, element->name);
694
695         g_static_rw_lock_reader_lock(&element_lock);
696
697         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
698
699         if (node != NULL)
700                 g_node_traverse(node, G_PRE_ORDER,
701                                 G_TRAVERSE_ALL, -1, update_element, NULL);
702
703         g_static_rw_lock_reader_unlock(&element_lock);
704 }
705
706 static void register_element(gpointer data, gpointer user_data)
707 {
708         struct connman_element *element = data;
709         const gchar *basepath;
710         GSList *list;
711         GNode *node;
712
713         g_static_rw_lock_writer_lock(&element_lock);
714
715         connman_element_lock(element);
716
717         if (element->parent) {
718                 node = g_node_find(element_root, G_PRE_ORDER,
719                                         G_TRAVERSE_ALL, element->parent);
720                 basepath = element->parent->path;
721
722                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
723                         element->subtype = element->parent->subtype;
724         } else {
725                 node = element_root;
726                 basepath = "";
727         }
728
729         element->path = g_strdup_printf("%s/%s", basepath, element->name);
730
731         connman_element_unlock(element);
732
733         DBG("element %p path %s", element, element->path);
734
735         g_node_append_data(node, element);
736
737         if (g_dbus_register_interface(connection, element->path,
738                                         CONNMAN_ELEMENT_INTERFACE,
739                                         element_methods, element_signals,
740                                         NULL, element, NULL) == FALSE)
741                 connman_error("Failed to register %s", element->path);
742
743         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
744                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
745                                 DBUS_TYPE_OBJECT_PATH, &element->path,
746                                                         DBUS_TYPE_INVALID);
747
748         g_static_rw_lock_writer_unlock(&element_lock);
749
750         __connman_element_store(element);
751
752         g_static_rw_lock_writer_lock(&element_lock);
753
754         for (list = driver_list; list; list = list->next) {
755                 struct connman_driver *driver = list->data;
756
757                 if (match_driver(element, driver) == FALSE)
758                         continue;
759
760                 DBG("driver %p name %s", driver, driver->name);
761
762                 if (driver->probe(element) == 0) {
763                         connman_element_lock(element);
764                         element->driver = driver;
765                         connman_element_unlock(element);
766                         break;
767                 }
768         }
769
770         g_static_rw_lock_writer_unlock(&element_lock);
771 }
772
773 static gboolean remove_element(GNode *node, gpointer user_data)
774 {
775         struct connman_element *element = node->data;
776         struct connman_element *root = user_data;
777
778         DBG("element %p name %s", element, element->name);
779
780         if (element == root)
781                 return FALSE;
782
783         if (element->driver) {
784                 if (element->driver->remove)
785                         element->driver->remove(element);
786
787                 connman_element_lock(element);
788                 element->driver = NULL;
789                 connman_element_unlock(element);
790         }
791
792         if (node != NULL) {
793                 g_node_unlink(node);
794                 g_node_destroy(node);
795         }
796
797         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
798                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
799                                 DBUS_TYPE_OBJECT_PATH, &element->path,
800                                                         DBUS_TYPE_INVALID);
801
802         g_dbus_unregister_interface(connection, element->path,
803                                                 CONNMAN_ELEMENT_INTERFACE);
804
805         connman_element_unref(element);
806
807         return FALSE;
808 }
809
810 static void unregister_element(gpointer data, gpointer user_data)
811 {
812         struct connman_element *element = data;
813         GNode *node;
814
815         DBG("element %p name %s", element, element->name);
816
817         g_static_rw_lock_writer_lock(&element_lock);
818
819         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
820
821         if (node != NULL)
822                 g_node_traverse(node, G_POST_ORDER,
823                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
824
825         g_static_rw_lock_writer_unlock(&element_lock);
826 }
827
828 static void unregister_children(gpointer data, gpointer user_data)
829 {
830         struct connman_element *element = data;
831         GNode *node;
832
833         DBG("element %p name %s", element, element->name);
834
835         g_static_rw_lock_writer_lock(&element_lock);
836
837         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
838
839         if (node != NULL)
840                 g_node_traverse(node, G_POST_ORDER,
841                                 G_TRAVERSE_ALL, -1, remove_element, element);
842
843         g_static_rw_lock_writer_unlock(&element_lock);
844 }
845
846 int __connman_element_init(DBusConnection *conn, const char *device)
847 {
848         struct connman_element *element;
849
850         DBG("conn %p", conn);
851
852         connection = dbus_connection_ref(conn);
853         if (connection == NULL)
854                 return -EIO;
855
856         device_filter = g_strdup(device);
857
858         g_static_rw_lock_writer_lock(&element_lock);
859
860         element = connman_element_create();
861
862         element->name = g_strdup("root");
863         element->path = g_strdup("/");
864         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
865
866         element_root = g_node_new(element);
867
868         g_static_rw_lock_writer_unlock(&element_lock);
869
870         thread_register = g_thread_pool_new(register_element,
871                                                         NULL, 1, FALSE, NULL);
872         thread_unregister = g_thread_pool_new(unregister_element,
873                                                         NULL, 1, FALSE, NULL);
874         thread_unregister_children = g_thread_pool_new(unregister_children,
875                                                         NULL, 1, FALSE, NULL);
876
877         return 0;
878 }
879
880 static gboolean free_driver(GNode *node, gpointer data)
881 {
882         struct connman_element *element = node->data;
883
884         DBG("element %p name %s", element, element->name);
885
886         if (element->driver) {
887                 if (element->driver->remove)
888                         element->driver->remove(element);
889
890                 connman_element_lock(element);
891                 element->driver = NULL;
892                 connman_element_unlock(element);
893         }
894
895         return FALSE;
896 }
897
898 static gboolean free_node(GNode *node, gpointer data)
899 {
900         struct connman_element *element = node->data;
901
902         DBG("element %p name %s", element, element->name);
903
904         if (g_node_depth(node) > 1)
905                 g_thread_pool_push(thread_unregister, element, NULL);
906
907         return FALSE;
908 }
909
910 void __connman_element_cleanup(void)
911 {
912         DBG("");
913
914         g_thread_pool_free(thread_register, TRUE, TRUE);
915         thread_register = NULL;
916
917         g_static_rw_lock_writer_lock(&element_lock);
918         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
919                                                         free_driver, NULL);
920         g_static_rw_lock_writer_unlock(&element_lock);
921
922         g_static_rw_lock_writer_lock(&element_lock);
923         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
924                                                         free_node, NULL);
925         g_static_rw_lock_writer_unlock(&element_lock);
926
927         g_thread_pool_free(thread_unregister, FALSE, TRUE);
928         thread_unregister = NULL;
929
930         g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
931         thread_unregister_children = NULL;
932
933         g_static_rw_lock_writer_lock(&element_lock);
934         g_node_destroy(element_root);
935         element_root = NULL;
936         g_static_rw_lock_writer_unlock(&element_lock);
937
938         g_free(device_filter);
939
940         dbus_connection_unref(connection);
941 }