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