Fully integrate the usage of resolver element
[framework/connectivity/connman.git] / 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 driver_lock = G_STATIC_RW_LOCK_INIT;
36 static GSList *driver_list = NULL;
37 static GThreadPool *driver_thread;
38
39 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
40 static GNode *element_root = NULL;
41 static GThreadPool *element_thread;
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_CONNECTION:
67                 return "42";
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->ipv4.address != NULL)
178                 append_entry(&dict, "IPv4.Address",
179                                 DBUS_TYPE_STRING, &element->ipv4.address);
180         if (element->ipv4.netmask != NULL)
181                 append_entry(&dict, "IPv4.Netmask",
182                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
183         if (element->ipv4.gateway != NULL)
184                 append_entry(&dict, "IPv4.Gateway",
185                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
186
187         for (list = element->properties; list; list = list->next) {
188                 struct connman_property *property = list->data;
189
190                 append_property(&dict, property);
191         }
192
193         dbus_message_iter_close_container(&array, &dict);
194
195         return reply;
196 }
197
198 static GDBusMethodTable element_methods[] = {
199         { "GetProperties", "", "a{sv}", get_properties },
200         { },
201 };
202
203 struct append_filter {
204         enum connman_element_type type;
205         DBusMessageIter *iter;
206 };
207
208 static gboolean append_path(GNode *node, gpointer data)
209 {
210         struct connman_element *element = node->data;
211         struct append_filter *filter = data;
212
213         DBG("element %p name %s", element, element->name);
214
215         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
216                 return FALSE;
217
218         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
219                                         filter->type != element->type)
220                 return FALSE;
221
222         dbus_message_iter_append_basic(filter->iter,
223                                 DBUS_TYPE_OBJECT_PATH, &element->path);
224
225         return FALSE;
226 }
227
228 void __connman_element_list(enum connman_element_type type,
229                                                 DBusMessageIter *iter)
230 {
231         struct append_filter filter = { type, iter };
232
233         DBG("");
234
235         g_static_rw_lock_reader_lock(&element_lock);
236         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
237                                                         append_path, &filter);
238         g_static_rw_lock_reader_unlock(&element_lock);
239 }
240
241 static gint compare_priority(gconstpointer a, gconstpointer b)
242 {
243         const struct connman_driver *driver1 = a;
244         const struct connman_driver *driver2 = b;
245
246         return driver2->priority - driver1->priority;
247 }
248
249 int connman_driver_register(struct connman_driver *driver)
250 {
251         DBG("driver %p name %s", driver, driver->name);
252
253         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
254                 return -1;
255
256         if (!driver->probe)
257                 return -EINVAL;
258
259         g_static_rw_lock_writer_lock(&driver_lock);
260         driver_list = g_slist_insert_sorted(driver_list, driver,
261                                                         compare_priority);
262         g_static_rw_lock_writer_unlock(&driver_lock);
263
264         g_thread_pool_push(driver_thread, driver, NULL);
265
266         return 0;
267 }
268
269 static gboolean remove_driver(GNode *node, gpointer data)
270 {
271         struct connman_element *element = node->data;
272         struct connman_driver *driver = data;
273
274         DBG("element %p name %s", element, element->name);
275
276         if (element->driver == driver) {
277                 if (driver->remove)
278                         driver->remove(element);
279                 element->driver = NULL;
280         }
281
282         return FALSE;
283 }
284
285 void connman_driver_unregister(struct connman_driver *driver)
286 {
287         DBG("driver %p name %s", driver, driver->name);
288
289         g_static_rw_lock_reader_lock(&element_lock);
290         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
291                                                         remove_driver, driver);
292         g_static_rw_lock_reader_unlock(&element_lock);
293
294         g_static_rw_lock_writer_lock(&driver_lock);
295         driver_list = g_slist_remove(driver_list, driver);
296         g_static_rw_lock_writer_unlock(&driver_lock);
297 }
298
299 struct connman_element *connman_element_create(void)
300 {
301         struct connman_element *element;
302
303         element = g_new0(struct connman_element, 1);
304
305         DBG("element %p", element);
306
307         element->refcount = 1;
308
309         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
310         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
311         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
312
313         element->netdev.index = -1;
314
315         return element;
316 }
317
318 struct connman_element *connman_element_ref(struct connman_element *element)
319 {
320         DBG("element %p name %s refcount %d", element, element->name,
321                                 g_atomic_int_get(&element->refcount) + 1);
322
323         g_atomic_int_inc(&element->refcount);
324
325         return element;
326 }
327
328 void connman_element_unref(struct connman_element *element)
329 {
330         DBG("element %p name %s refcount %d", element, element->name,
331                                 g_atomic_int_get(&element->refcount) - 1);
332
333         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
334                 GSList *list;
335
336                 for (list = element->properties; list; list = list->next) {
337                         struct connman_property *property = list->data;
338                         if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
339                                         property->type == DBUS_TYPE_STRING)
340                                 g_free(property->value);
341                         g_free(property);
342                         list->data = NULL;
343                 }
344                 g_slist_free(element->properties);
345
346                 g_free(element->ipv4.address);
347                 g_free(element->ipv4.netmask);
348                 g_free(element->ipv4.gateway);
349                 g_free(element->ipv4.network);
350                 g_free(element->ipv4.broadcast);
351                 g_free(element->ipv4.nameserver);
352                 g_free(element->netdev.name);
353                 g_free(element->path);
354                 g_free(element->name);
355                 g_free(element);
356         }
357 }
358
359 int connman_element_add_static_property(struct connman_element *element,
360                                 const char *name, int type, const void *value)
361 {
362         struct connman_property *property;
363
364         DBG("element %p name %s", element, element->name);
365
366         if (type != DBUS_TYPE_STRING)
367                 return -EINVAL;
368
369         property = g_try_new0(struct connman_property, 1);
370         if (property == NULL)
371                 return -ENOMEM;
372
373         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
374
375         property->name = g_strdup(name);
376         property->type = type;
377
378         DBG("name %s type %d value %p", name, type, value);
379
380         switch (type) {
381         case DBUS_TYPE_STRING:
382                 property->value = g_strdup(*((const char **) value));
383                 break;
384         }
385
386         element->properties = g_slist_append(element->properties, property);
387
388         return 0;
389 }
390
391 int connman_element_set_property(struct connman_element *element,
392                         enum connman_property_type type, const void *value)
393 {
394         switch (type) {
395         case CONNMAN_PROPERTY_TYPE_INVALID:
396                 return -EINVAL;
397         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
398                 g_free(element->ipv4.address);
399                 element->ipv4.address = g_strdup(*((const char **) value));
400                 break;
401         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
402                 g_free(element->ipv4.netmask);
403                 element->ipv4.netmask = g_strdup(*((const char **) value));
404                 break;
405         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
406                 g_free(element->ipv4.gateway);
407                 element->ipv4.gateway = g_strdup(*((const char **) value));
408                 break;
409         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
410                 g_free(element->ipv4.nameserver);
411                 element->ipv4.nameserver = g_strdup(*((const char **) value));
412                 break;
413         }
414
415         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
416                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
417                                 DBUS_TYPE_OBJECT_PATH, &element->path,
418                                                         DBUS_TYPE_INVALID);
419
420         return 0;
421 }
422
423 int connman_element_get_value(struct connman_element *element,
424                                 enum connman_property_type type, void *value)
425 {
426         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
427                 return -EINVAL;
428
429         switch (type) {
430         case CONNMAN_PROPERTY_TYPE_INVALID:
431                 return -EINVAL;
432         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
433                 if (element->ipv4.address == NULL)
434                         return connman_element_get_value(element->parent,
435                                                                 type, value);
436                 *((char **) value) = element->ipv4.address;
437                 break;
438         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
439                 if (element->ipv4.netmask == NULL)
440                         return connman_element_get_value(element->parent,
441                                                                 type, value);
442                 *((char **) value) = element->ipv4.netmask;
443                 break;
444         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
445                 if (element->ipv4.gateway == NULL)
446                         return connman_element_get_value(element->parent,
447                                                                 type, value);
448                 *((char **) value) = element->ipv4.gateway;
449                 break;
450         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
451                 if (element->ipv4.nameserver == NULL)
452                         return connman_element_get_value(element->parent,
453                                                                 type, value);
454                 *((char **) value) = element->ipv4.nameserver;
455                 break;
456         }
457
458         return 0;
459 }
460
461 int connman_element_register(struct connman_element *element,
462                                         struct connman_element *parent)
463 {
464         GNode *node;
465         const gchar *basepath;
466
467         DBG("element %p name %s parent %p", element, element->name, parent);
468
469         if (connman_element_ref(element) == NULL)
470                 return -1;
471
472         __connman_element_load(element);
473
474         g_static_rw_lock_writer_lock(&element_lock);
475
476         if (parent) {
477                 node = g_node_find(element_root, G_PRE_ORDER,
478                                                 G_TRAVERSE_ALL, parent);
479                 basepath = parent->path;
480
481                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
482                         element->subtype = parent->subtype;
483         } else {
484                 node = element_root;
485                 basepath = "";
486         }
487
488         if (element->name == NULL) {
489                 switch (element->type) {
490                 case CONNMAN_ELEMENT_TYPE_IPV4:
491                         element->name = g_strdup("ipv4");
492                         break;
493                 case CONNMAN_ELEMENT_TYPE_IPV6:
494                         element->name = g_strdup("ipv6");
495                         break;
496                 case CONNMAN_ELEMENT_TYPE_DHCP:
497                         element->name = g_strdup("dhcp");
498                         break;
499                 case CONNMAN_ELEMENT_TYPE_BOOTP:
500                         element->name = g_strdup("bootp");
501                         break;
502                 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
503                         element->name = g_strdup("zeroconf");
504                         break;
505                 case CONNMAN_ELEMENT_TYPE_RESOLVER:
506                         element->name = g_strdup("resolver");
507                         break;
508                 default:
509                         break;
510                 }
511         }
512
513         element->path = g_strdup_printf("%s/%s", basepath, element->name);
514         element->parent = parent;
515
516         DBG("element %p path %s", element, element->path);
517
518         g_node_append_data(node, element);
519
520         g_static_rw_lock_writer_unlock(&element_lock);
521
522         __connman_element_store(element);
523
524         g_dbus_register_interface(connection, element->path,
525                                         CONNMAN_ELEMENT_INTERFACE,
526                                         element_methods, NULL, NULL,
527                                                         element, NULL);
528
529         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
530                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
531                                 DBUS_TYPE_OBJECT_PATH, &element->path,
532                                                         DBUS_TYPE_INVALID);
533
534         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
535                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
536                                 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
537                                 DBUS_TYPE_OBJECT_PATH, &element->path,
538                                                         DBUS_TYPE_INVALID);
539
540         g_thread_pool_push(element_thread, element, NULL);
541
542         return 0;
543 }
544
545 void connman_element_unregister(struct connman_element *element)
546 {
547         GNode *node;
548
549         DBG("element %p name %s", element, element->name);
550
551         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
552                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
553                                 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
554                                 DBUS_TYPE_OBJECT_PATH, &element->path,
555                                                         DBUS_TYPE_INVALID);
556
557         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
558                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
559                                 DBUS_TYPE_OBJECT_PATH, &element->path,
560                                                         DBUS_TYPE_INVALID);
561
562         g_dbus_unregister_interface(connection, element->path,
563                                                 CONNMAN_ELEMENT_INTERFACE);
564
565         g_static_rw_lock_writer_lock(&element_lock);
566
567         if (element->driver) {
568                 if (element->driver->remove)
569                         element->driver->remove(element);
570                 element->driver = NULL;
571         }
572
573         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
574         if (node != NULL) {
575                 g_node_unlink(node);
576                 g_node_destroy(node);
577         }
578
579         g_static_rw_lock_writer_unlock(&element_lock);
580
581         connman_element_unref(element);
582 }
583
584 void connman_element_update(struct connman_element *element)
585 {
586         DBG("element %p name %s", element, element->name);
587
588         g_static_rw_lock_reader_lock(&element_lock);
589
590         if (element->driver && element->driver->update)
591                 element->driver->update(element);
592
593         g_static_rw_lock_reader_unlock(&element_lock);
594
595         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
596                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
597                                 DBUS_TYPE_OBJECT_PATH, &element->path,
598                                                         DBUS_TYPE_INVALID);
599 }
600
601 static inline void set_driver(struct connman_element *element,
602                                                 struct connman_driver *driver)
603 {
604         g_static_rw_lock_reader_lock(&element_lock);
605         element->driver = driver;
606         g_static_rw_lock_reader_unlock(&element_lock);
607 }
608
609 static gboolean match_driver(struct connman_element *element,
610                                         struct connman_driver *driver)
611 {
612         if (element->type != driver->type &&
613                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
614                 return FALSE;
615
616         if (element->subtype == driver->subtype ||
617                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
618                 return TRUE;
619
620         return FALSE;
621 }
622
623 static gboolean probe_driver(GNode *node, gpointer data)
624 {
625         struct connman_element *element = node->data;
626         struct connman_driver *driver = data;
627
628         DBG("element %p name %s", element, element->name);
629
630         if (!element->driver && match_driver(element, driver) == TRUE) {
631                 element->driver = driver;
632
633                 if (driver->probe(element) < 0)
634                         element->driver = NULL;
635         }
636
637         return FALSE;
638 }
639
640 static void driver_probe(gpointer data, gpointer user_data)
641 {
642         struct connman_driver *driver = data;
643
644         DBG("driver %p name %s", driver, driver->name);
645
646         g_static_rw_lock_reader_lock(&element_lock);
647         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
648                                                         probe_driver, driver);
649         g_static_rw_lock_reader_unlock(&element_lock);
650 }
651
652 static void element_probe(gpointer data, gpointer user_data)
653 {
654         struct connman_element *element = data;
655         GSList *list;
656
657         DBG("element %p name %s", element, element->name);
658
659         if (connman_element_ref(element) == NULL)
660                 return;
661
662         g_static_rw_lock_reader_lock(&driver_lock);
663
664         for (list = driver_list; list; list = list->next) {
665                 struct connman_driver *driver = list->data;
666
667                 DBG("driver %p name %s", driver, driver->name);
668
669                 set_driver(element, driver);
670
671                 if (match_driver(element, driver) == TRUE &&
672                                                 driver->probe(element) == 0)
673                         break;
674
675                 set_driver(element, NULL);
676         }
677
678         g_static_rw_lock_reader_unlock(&driver_lock);
679
680         connman_element_unref(element);
681 }
682
683 int __connman_element_init(DBusConnection *conn)
684 {
685         struct connman_element *element;
686
687         DBG("conn %p", conn);
688
689         connection = dbus_connection_ref(conn);
690         if (connection == NULL)
691                 return -EIO;
692
693         g_static_rw_lock_writer_lock(&element_lock);
694
695         element = connman_element_create();
696
697         element->name = g_strdup("root");
698         element->path = g_strdup("/");
699         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
700
701         element_root = g_node_new(element);
702
703         g_static_rw_lock_writer_unlock(&element_lock);
704
705         element_thread = g_thread_pool_new(element_probe, NULL, 1, FALSE, NULL);
706
707         driver_thread = g_thread_pool_new(driver_probe, NULL, 1, FALSE, NULL);
708
709         return 0;
710 }
711
712 static gboolean free_node(GNode *node, gpointer data)
713 {
714         struct connman_element *element = node->data;
715
716         DBG("element %p name %s", element, element->name);
717
718         g_dbus_unregister_interface(connection, element->path,
719                                                 CONNMAN_ELEMENT_INTERFACE);
720
721         if (element->driver) {
722                 if (element->driver->remove)
723                         element->driver->remove(element);
724                 element->driver = NULL;
725         }
726
727         connman_element_unref(element);
728
729         node->data = NULL;
730
731         return FALSE;
732 }
733
734 void __connman_element_cleanup(void)
735 {
736         DBG("");
737
738         g_thread_pool_free(driver_thread, TRUE, TRUE);
739
740         g_thread_pool_free(element_thread, TRUE, TRUE);
741
742         g_static_rw_lock_writer_lock(&element_lock);
743
744         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
745                                                         free_node, NULL);
746
747         g_node_destroy(element_root);
748         element_root = NULL;
749
750         g_static_rw_lock_writer_unlock(&element_lock);
751
752         dbus_connection_unref(connection);
753 }