Provide detailed device and network properties
[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 #include <stdarg.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 static DBusConnection *connection;
36
37 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
38 static GNode *element_root = NULL;
39
40 static GSList *driver_list = NULL;
41
42 static GThreadPool *thread_register = NULL;
43 static GThreadPool *thread_unregister = NULL;
44 static GThreadPool *thread_unregister_children = NULL;
45
46 static gchar *device_filter = NULL;
47
48 static struct {
49         enum connman_property_id id;
50         int type;
51         const char *name;
52         const void *value;
53 } propid_table[] = {
54         { CONNMAN_PROPERTY_ID_IPV4_METHOD,
55                 DBUS_TYPE_STRING, "IPv4.Method", "dhcp" },
56         { CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
57                 DBUS_TYPE_STRING, "IPv4.Address" },
58         { CONNMAN_PROPERTY_ID_IPV4_NETMASK,
59                 DBUS_TYPE_STRING, "IPv4.Netmask" },
60         { CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
61                 DBUS_TYPE_STRING, "IPv4.Gateway" },
62         { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
63                 DBUS_TYPE_STRING, "IPv4.Nameserver" },
64
65         { CONNMAN_PROPERTY_ID_WIFI_SECURITY,
66                 DBUS_TYPE_STRING, "WiFi.Security" },
67         { CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE,
68                 DBUS_TYPE_STRING, "WiFi.Passphrase" },
69
70         { }
71 };
72
73 static int propid2type(enum connman_property_id id)
74 {
75         int i;
76
77         for (i = 0; propid_table[i].name; i++) {
78                 if (propid_table[i].id == id)
79                         return propid_table[i].type;
80         }
81
82         return DBUS_TYPE_INVALID;
83 }
84
85 static const char *propid2name(enum connman_property_id id)
86 {
87         int i;
88
89         for (i = 0; propid_table[i].name; i++) {
90                 if (propid_table[i].id == id)
91                         return propid_table[i].name;
92         }
93
94         return NULL;
95 }
96
97 static const char *type2string(enum connman_element_type type)
98 {
99         switch (type) {
100         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
101                 return "unknown";
102         case CONNMAN_ELEMENT_TYPE_ROOT:
103                 return "root";
104         case CONNMAN_ELEMENT_TYPE_PROFILE:
105                 return "profile";
106         case CONNMAN_ELEMENT_TYPE_DEVICE:
107                 return "device";
108         case CONNMAN_ELEMENT_TYPE_NETWORK:
109                 return "network";
110         case CONNMAN_ELEMENT_TYPE_IPV4:
111                 return "ipv4";
112         case CONNMAN_ELEMENT_TYPE_IPV6:
113                 return "ipv6";
114         case CONNMAN_ELEMENT_TYPE_DHCP:
115                 return "dhcp";
116         case CONNMAN_ELEMENT_TYPE_BOOTP:
117                 return "bootp";
118         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
119                 return "zeroconf";
120         case CONNMAN_ELEMENT_TYPE_RESOLVER:
121                 return "resolver";
122         case CONNMAN_ELEMENT_TYPE_INTERNET:
123                 return "internet";
124         }
125
126         return NULL;
127 }
128
129 static const char *subtype2string(enum connman_element_subtype type)
130 {
131         switch (type) {
132         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
133                 return "unknown";
134         case CONNMAN_ELEMENT_SUBTYPE_FAKE:
135                 return "fake";
136         case CONNMAN_ELEMENT_SUBTYPE_NETWORK:
137                 return "network";
138         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
139                 return "ethernet";
140         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
141                 return "wifi";
142         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
143                 return "wimax";
144         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
145                 return "modem";
146         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
147                 return "bluetooth";
148         }
149
150         return NULL;
151 }
152
153 static void append_property(DBusMessageIter *dict,
154                                 struct connman_property *property)
155 {
156         if (property->value == NULL)
157                 return;
158
159         if (property->type == DBUS_TYPE_ARRAY)
160                 connman_dbus_dict_append_array(dict, property->name,
161                         property->subtype, &property->value, property->size);
162         else
163                 connman_dbus_dict_append_variant(dict, property->name,
164                                         property->type, &property->value);
165 }
166
167 static void add_common_properties(struct connman_element *element,
168                                                 DBusMessageIter *dict)
169 {
170         GSList *list;
171
172         if (element->priority > 0)
173                 connman_dbus_dict_append_variant(dict, "Priority",
174                                         DBUS_TYPE_UINT16, &element->priority);
175
176         if (element->ipv4.address != NULL)
177                 connman_dbus_dict_append_variant(dict, "IPv4.Address",
178                                 DBUS_TYPE_STRING, &element->ipv4.address);
179         if (element->ipv4.netmask != NULL)
180                 connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
181                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
182         if (element->ipv4.gateway != NULL)
183                 connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
184                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
185
186         if (element->wifi.security != NULL) {
187                 const char *passphrase = "";
188
189                 connman_dbus_dict_append_variant(dict, "WiFi.Security",
190                                 DBUS_TYPE_STRING, &element->wifi.security);
191
192                 if (element->wifi.passphrase != NULL)
193                         passphrase = element->wifi.passphrase;
194
195                 connman_dbus_dict_append_variant(dict, "WiFi.Passphrase",
196                                 DBUS_TYPE_STRING, &passphrase);
197         }
198
199         connman_element_lock(element);
200
201         for (list = element->properties; list; list = list->next) {
202                 struct connman_property *property = list->data;
203
204                 append_property(dict, property);
205         }
206
207         connman_element_unlock(element);
208 }
209
210 static DBusMessage *get_properties(DBusConnection *conn,
211                                         DBusMessage *msg, void *data)
212 {
213         struct connman_element *element = data;
214         DBusMessage *reply;
215         DBusMessageIter array, dict;
216         const char *str;
217
218         DBG("conn %p", conn);
219
220         reply = dbus_message_new_method_return(msg);
221         if (reply == NULL)
222                 return NULL;
223
224         dbus_message_iter_init_append(reply, &array);
225
226         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
227                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
228                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
229                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
230
231         if (element->parent != NULL &&
232                         element->parent->type != CONNMAN_ELEMENT_TYPE_ROOT) {
233                 connman_dbus_dict_append_variant(&dict, "Parent",
234                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
235         }
236
237         str = type2string(element->type);
238         if (str != NULL)
239                 connman_dbus_dict_append_variant(&dict, "Type",
240                                                 DBUS_TYPE_STRING, &str);
241         str = subtype2string(element->subtype);
242         if (str != NULL)
243                 connman_dbus_dict_append_variant(&dict, "Subtype",
244                                                 DBUS_TYPE_STRING, &str);
245
246         connman_dbus_dict_append_variant(&dict, "Enabled",
247                                         DBUS_TYPE_BOOLEAN, &element->enabled);
248
249         add_common_properties(element, &dict);
250
251         dbus_message_iter_close_container(&array, &dict);
252
253         return reply;
254 }
255
256 static DBusMessage *get_device_properties(DBusConnection *conn,
257                                         DBusMessage *msg, void *data)
258 {
259         struct connman_element *element = data;
260         DBusMessage *reply;
261         DBusMessageIter array, dict;
262         const char *str;
263
264         DBG("conn %p", conn);
265
266         reply = dbus_message_new_method_return(msg);
267         if (reply == NULL)
268                 return NULL;
269
270         dbus_message_iter_init_append(reply, &array);
271
272         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
273                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
274                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
275                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
276
277         str = subtype2string(element->subtype);
278         if (str != NULL)
279                 connman_dbus_dict_append_variant(&dict, "Type",
280                                                 DBUS_TYPE_STRING, &str);
281
282         connman_dbus_dict_append_variant(&dict, "Powered",
283                                         DBUS_TYPE_BOOLEAN, &element->enabled);
284
285         add_common_properties(element, &dict);
286
287         dbus_message_iter_close_container(&array, &dict);
288
289         return reply;
290 }
291
292 static DBusMessage *get_network_properties(DBusConnection *conn,
293                                         DBusMessage *msg, void *data)
294 {
295         struct connman_element *element = data;
296         DBusMessage *reply;
297         DBusMessageIter array, dict;
298
299         DBG("conn %p", conn);
300
301         reply = dbus_message_new_method_return(msg);
302         if (reply == NULL)
303                 return NULL;
304
305         dbus_message_iter_init_append(reply, &array);
306
307         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
308                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
309                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
310                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
311
312         connman_dbus_dict_append_variant(&dict, "Connected",
313                                         DBUS_TYPE_BOOLEAN, &element->enabled);
314
315         add_common_properties(element, &dict);
316
317         dbus_message_iter_close_container(&array, &dict);
318
319         return reply;
320 }
321
322 static DBusMessage *set_property(DBusConnection *conn,
323                                         DBusMessage *msg, void *data)
324 {
325         struct connman_element *element = data;
326         DBusMessageIter iter;
327         DBusMessageIter value;
328         const char *name;
329         GSList *list;
330
331         DBG("conn %p", conn);
332
333         if (dbus_message_iter_init(msg, &iter) == FALSE)
334                 return __connman_error_invalid_arguments(msg);
335
336         dbus_message_iter_get_basic(&iter, &name);
337         dbus_message_iter_next(&iter);
338         dbus_message_iter_recurse(&iter, &value);
339
340         if (__connman_security_check_privileges(msg) < 0)
341                 return __connman_error_permission_denied(msg);
342
343         connman_element_lock(element);
344
345         for (list = element->properties; list; list = list->next) {
346                 struct connman_property *property = list->data;
347                 const char *str;
348
349                 if (g_str_equal(property->name, name) == FALSE)
350                         continue;
351
352                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
353                         continue;
354
355                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
356
357                 if (property->type == DBUS_TYPE_STRING) {
358                         dbus_message_iter_get_basic(&value, &str);
359                         g_free(property->value);
360                         property->value = g_strdup(str);
361                 } else
362                         property->value = NULL;
363         }
364
365         connman_element_unlock(element);
366
367         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
368 }
369
370 static DBusMessage *clear_property(DBusConnection *conn,
371                                         DBusMessage *msg, void *data)
372 {
373         struct connman_element *element = data;
374         const char *name;
375         GSList *list;
376
377         DBG("conn %p", conn);
378
379         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
380                                                 DBUS_TYPE_INVALID) == FALSE)
381                 return __connman_error_invalid_arguments(msg);
382
383         if (__connman_security_check_privileges(msg) < 0)
384                 return __connman_error_permission_denied(msg);
385
386         connman_element_lock(element);
387
388         for (list = element->properties; list; list = list->next) {
389                 struct connman_property *property = list->data;
390
391                 if (g_str_equal(property->name, name) == FALSE)
392                         continue;
393
394                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
395                         continue;
396
397                 if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)
398                         continue;
399
400                 property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE;
401
402                 if (property->type == DBUS_TYPE_STRING)
403                         g_free(property->value);
404
405                 property->value = NULL;
406         }
407
408         connman_element_unlock(element);
409
410         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
411 }
412
413 static DBusMessage *do_update(DBusConnection *conn,
414                                         DBusMessage *msg, void *data)
415 {
416         struct connman_element *element = data;
417
418         DBG("conn %p", conn);
419
420         if (element->enabled == FALSE)
421                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
422
423         if (element->driver && element->driver->update) {
424                 DBG("Calling update callback");
425                 element->driver->update(element);
426         }
427
428         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
429 }
430
431 static DBusMessage *do_enable(DBusConnection *conn,
432                                         DBusMessage *msg, void *data)
433 {
434         struct connman_element *element = data;
435
436         DBG("conn %p", conn);
437
438         if (element->enabled == TRUE)
439                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
440
441         if (element->driver && element->driver->enable) {
442                 DBG("Calling enable callback");
443                 if (element->driver->enable(element) < 0)
444                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
445         }
446
447         element->enabled = TRUE;
448
449         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
450                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
451                                 DBUS_TYPE_OBJECT_PATH, &element->path,
452                                                         DBUS_TYPE_INVALID);
453
454         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
455 }
456
457 static DBusMessage *do_disable(DBusConnection *conn,
458                                         DBusMessage *msg, void *data)
459 {
460         struct connman_element *element = data;
461
462         DBG("conn %p", conn);
463
464         if (element->enabled == FALSE)
465                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
466
467         if (element->driver && element->driver->disable) {
468                 DBG("Calling disable callback");
469                 if (element->driver->disable(element) < 0)
470                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
471         }
472
473         element->enabled = FALSE;
474
475         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
476                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
477                                 DBUS_TYPE_OBJECT_PATH, &element->path,
478                                                         DBUS_TYPE_INVALID);
479
480         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
481 }
482
483 static GDBusMethodTable element_methods[] = {
484         { "GetProperties", "",   "a{sv}", get_properties },
485         { "SetProperty",   "sv", "",      set_property   },
486         { "ClearProperty", "s",  "",      clear_property },
487         { "Update",        "",   "",      do_update      },
488         { "Enable",        "",   "",      do_enable      },
489         { "Disable",       "",   "",      do_disable     },
490         { },
491 };
492
493 static GDBusSignalTable element_signals[] = {
494         { "PropertyChanged", "sv" },
495         { },
496 };
497
498 static GDBusMethodTable device_methods[] = {
499         { "GetProperties", "",   "a{sv}", get_device_properties },
500         { },
501 };
502
503 static GDBusMethodTable network_methods[] = {
504         { "GetProperties", "",   "a{sv}", get_network_properties },
505         { },
506 };
507
508 struct append_filter {
509         enum connman_element_type type;
510         DBusMessageIter *iter;
511 };
512
513 static gboolean append_path(GNode *node, gpointer data)
514 {
515         struct connman_element *element = node->data;
516         struct append_filter *filter = data;
517
518         DBG("element %p name %s", element, element->name);
519
520         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
521                 return FALSE;
522
523         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
524                                         filter->type != element->type)
525                 return FALSE;
526
527         dbus_message_iter_append_basic(filter->iter,
528                                 DBUS_TYPE_OBJECT_PATH, &element->path);
529
530         return FALSE;
531 }
532
533 void __connman_element_list(enum connman_element_type type,
534                                                 DBusMessageIter *iter)
535 {
536         struct append_filter filter = { type, iter };
537
538         DBG("");
539
540         g_static_rw_lock_reader_lock(&element_lock);
541         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
542                                                         append_path, &filter);
543         g_static_rw_lock_reader_unlock(&element_lock);
544 }
545
546 static gint compare_priority(gconstpointer a, gconstpointer b)
547 {
548         const struct connman_driver *driver1 = a;
549         const struct connman_driver *driver2 = b;
550
551         return driver2->priority - driver1->priority;
552 }
553
554 static gboolean match_driver(struct connman_element *element,
555                                         struct connman_driver *driver)
556 {
557         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
558                 return FALSE;
559
560         if (element->type != driver->type &&
561                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
562                 return FALSE;
563
564         if (element->subtype == driver->subtype ||
565                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
566                 return TRUE;
567
568         return FALSE;
569 }
570
571 static gboolean probe_driver(GNode *node, gpointer data)
572 {
573         struct connman_element *element = node->data;
574         struct connman_driver *driver = data;
575
576         DBG("element %p name %s", element, element->name);
577
578         if (!element->driver && match_driver(element, driver) == TRUE) {
579                 if (driver->probe(element) < 0)
580                         return FALSE;
581
582                 connman_element_lock(element);
583                 element->driver = driver;
584                 connman_element_unlock(element);
585         }
586
587         return FALSE;
588 }
589
590 void __connman_driver_rescan(struct connman_driver *driver)
591 {
592         DBG("driver %p name %s", driver, driver->name);
593
594         if (!driver->probe)
595                 return;
596
597         g_static_rw_lock_writer_lock(&element_lock);
598
599         if (element_root != NULL)
600                 g_node_traverse(element_root, G_PRE_ORDER,
601                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
602
603         g_static_rw_lock_writer_unlock(&element_lock);
604 }
605
606 /**
607  * connman_driver_register:
608  * @driver: driver definition
609  *
610  * Register a new driver
611  *
612  * Returns: %0 on success
613  */
614 int connman_driver_register(struct connman_driver *driver)
615 {
616         DBG("driver %p name %s", driver, driver->name);
617
618         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
619                 return -EINVAL;
620
621         if (!driver->probe)
622                 return -EINVAL;
623
624         g_static_rw_lock_writer_lock(&element_lock);
625
626         driver_list = g_slist_insert_sorted(driver_list, driver,
627                                                         compare_priority);
628
629         if (element_root != NULL)
630                 g_node_traverse(element_root, G_PRE_ORDER,
631                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
632
633         g_static_rw_lock_writer_unlock(&element_lock);
634
635         return 0;
636 }
637
638 static gboolean remove_driver(GNode *node, gpointer data)
639 {
640         struct connman_element *element = node->data;
641         struct connman_driver *driver = data;
642
643         DBG("element %p name %s", element, element->name);
644
645         if (element->driver == driver) {
646                 if (driver->remove)
647                         driver->remove(element);
648
649                 connman_element_lock(element);
650                 element->driver = NULL;
651                 connman_element_unlock(element);
652         }
653
654         return FALSE;
655 }
656
657 /**
658  * connman_driver_unregister:
659  * @driver: driver definition
660  *
661  * Remove a previously registered driver
662  */
663 void connman_driver_unregister(struct connman_driver *driver)
664 {
665         DBG("driver %p name %s", driver, driver->name);
666
667         g_static_rw_lock_writer_lock(&element_lock);
668
669         driver_list = g_slist_remove(driver_list, driver);
670
671         if (element_root != NULL)
672                 g_node_traverse(element_root, G_POST_ORDER,
673                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
674
675         g_static_rw_lock_writer_unlock(&element_lock);
676 }
677
678 /**
679  * connman_element_create:
680  * @name: element name
681  *
682  * Allocate a new element and assign the given #name to it. If the name
683  * is #NULL, it will be later on created based on the element type.
684  *
685  * Returns: a newly-allocated #connman_element structure
686  */
687 struct connman_element *connman_element_create(const char *name)
688 {
689         struct connman_element *element;
690
691         element = g_try_new0(struct connman_element, 1);
692         if (element == NULL)
693                 return NULL;
694
695         DBG("element %p", element);
696
697         element->refcount = 1;
698
699         g_static_mutex_init(&element->mutex);
700
701         element->name    = g_strdup(name);
702         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
703         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
704         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
705         element->index   = -1;
706         element->enabled = FALSE;
707
708         return element;
709 }
710
711 struct connman_element *connman_element_ref(struct connman_element *element)
712 {
713         DBG("element %p name %s refcount %d", element, element->name,
714                                 g_atomic_int_get(&element->refcount) + 1);
715
716         g_atomic_int_inc(&element->refcount);
717
718         return element;
719 }
720
721 static void free_properties(struct connman_element *element)
722 {
723         GSList *list;
724
725         DBG("element %p name %s", element, element->name);
726
727         connman_element_lock(element);
728
729         for (list = element->properties; list; list = list->next) {
730                 struct connman_property *property = list->data;
731
732                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) {
733                         if (property->type == DBUS_TYPE_STRING)
734                                 g_free(property->value);
735                         if (property->type == DBUS_TYPE_ARRAY &&
736                                         property->subtype == DBUS_TYPE_BYTE)
737                                 g_free(property->value);
738                 }
739
740                 g_free(property);
741         }
742
743         g_slist_free(element->properties);
744
745         element->properties = NULL;
746
747         connman_element_unlock(element);
748 }
749
750 void connman_element_unref(struct connman_element *element)
751 {
752         DBG("element %p name %s refcount %d", element, element->name,
753                                 g_atomic_int_get(&element->refcount) - 1);
754
755         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
756                 free_properties(element);
757                 g_free(element->ipv4.address);
758                 g_free(element->ipv4.netmask);
759                 g_free(element->ipv4.gateway);
760                 g_free(element->ipv4.network);
761                 g_free(element->ipv4.broadcast);
762                 g_free(element->ipv4.nameserver);
763                 g_free(element->path);
764                 g_free(element->name);
765                 g_free(element);
766         }
767 }
768
769 int connman_element_add_static_property(struct connman_element *element,
770                                 const char *name, int type, const void *value)
771 {
772         struct connman_property *property;
773
774         DBG("element %p name %s", element, element->name);
775
776         if (type != DBUS_TYPE_STRING)
777                 return -EINVAL;
778
779         property = g_try_new0(struct connman_property, 1);
780         if (property == NULL)
781                 return -ENOMEM;
782
783         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
784         property->id    = CONNMAN_PROPERTY_ID_INVALID;
785         property->name  = g_strdup(name);
786         property->type  = type;
787
788         DBG("name %s type %d value %p", name, type, value);
789
790         switch (type) {
791         case DBUS_TYPE_STRING:
792                 property->value = g_strdup(*((const char **) value));
793                 break;
794         }
795
796         connman_element_lock(element);
797         element->properties = g_slist_append(element->properties, property);
798         connman_element_unlock(element);
799
800         return 0;
801 }
802
803 int connman_element_add_static_array_property(struct connman_element *element,
804                         const char *name, int type, const void *value, int len)
805 {
806         struct connman_property *property;
807
808         DBG("element %p name %s", element, element->name);
809
810         if (type != DBUS_TYPE_BYTE)
811                 return -EINVAL;
812
813         property = g_try_new0(struct connman_property, 1);
814         if (property == NULL)
815                 return -ENOMEM;
816
817         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
818         property->id      = CONNMAN_PROPERTY_ID_INVALID;
819         property->name    = g_strdup(name);
820         property->type    = DBUS_TYPE_ARRAY;
821         property->subtype = type;
822
823         DBG("name %s type %d value %p", name, type, value);
824
825         switch (type) {
826         case DBUS_TYPE_BYTE:
827                 property->value = g_try_malloc(len);
828                 if (property->value != NULL) {
829                         memcpy(property->value,
830                                 *((const unsigned char **) value), len);
831                         property->size = len;
832                 }
833                 break;
834         }
835
836         connman_element_lock(element);
837         element->properties = g_slist_append(element->properties, property);
838         connman_element_unlock(element);
839
840         return 0;
841 }
842
843 static void *get_reference_value(struct connman_element *element,
844                                                 enum connman_property_id id)
845 {
846         GSList *list;
847
848         DBG("element %p name %s", element, element->name);
849
850         for (list = element->properties; list; list = list->next) {
851                 struct connman_property *property = list->data;
852
853                 if (property->id != id)
854                         continue;
855
856                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
857                         return property->value;
858         }
859
860         if (element->parent == NULL)
861                 return NULL;
862
863         return get_reference_value(element->parent, id);
864 }
865
866 static void set_reference_properties(struct connman_element *element)
867 {
868         GSList *list;
869
870         DBG("element %p name %s", element, element->name);
871
872         for (list = element->properties; list; list = list->next) {
873                 struct connman_property *property = list->data;
874
875                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
876                         continue;
877
878                 property->value = get_reference_value(element->parent,
879                                                                 property->id);
880         }
881 }
882
883 static struct connman_property *create_property(struct connman_element *element,
884                                                 enum connman_property_id id)
885 {
886         struct connman_property *property;
887         GSList *list;
888
889         DBG("element %p name %s", element, element->name);
890
891         connman_element_lock(element);
892
893         for (list = element->properties; list; list = list->next) {
894                 property = list->data;
895
896                 if (property->id == id)
897                         goto unlock;
898         }
899
900         property = g_try_new0(struct connman_property, 1);
901         if (property == NULL)
902                 goto unlock;
903
904         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
905         property->id    = id;
906         property->name  = g_strdup(propid2name(id));
907         property->type  = propid2type(id);
908
909         if (property->name == NULL) {
910                 g_free(property);
911                 property = NULL;
912                 goto unlock;
913         }
914
915         element->properties = g_slist_append(element->properties, property);
916
917 unlock:
918         connman_element_unlock(element);
919
920         return property;
921 }
922
923 static void create_default_properties(struct connman_element *element)
924 {
925         struct connman_property *property;
926         int i;
927
928         DBG("element %p name %s", element, element->name);
929
930         for (i = 0; propid_table[i].name; i++) {
931                 DBG("property %s", propid_table[i].name);
932
933                 property = create_property(element, propid_table[i].id);
934
935                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
936
937                 if (propid_table[i].type != DBUS_TYPE_STRING)
938                         continue;
939
940                 if (propid_table[i].value)
941                         property->value = g_strdup(propid_table[i].value);
942                 else
943                         property->value = g_strdup("");
944         }
945 }
946
947 static int define_properties_valist(struct connman_element *element,
948                                                                 va_list args)
949 {
950         enum connman_property_id id;
951
952         DBG("element %p name %s", element, element->name);
953
954         id = va_arg(args, enum connman_property_id);
955
956         while (id != CONNMAN_PROPERTY_ID_INVALID) {
957
958                 DBG("property %d", id);
959
960                 create_property(element, id);
961
962                 id = va_arg(args, enum connman_property_id);
963         }
964
965         return 0;
966 }
967
968 /**
969  * connman_element_define_properties:
970  * @element: an element
971  * @varargs: list of property identifiers
972  *
973  * Define the valid properties for an element.
974  *
975  * Returns: %0 on success
976  */
977 int connman_element_define_properties(struct connman_element *element, ...)
978 {
979         va_list args;
980         int err;
981
982         DBG("element %p name %s", element, element->name);
983
984         va_start(args, element);
985
986         err = define_properties_valist(element, args);
987
988         va_end(args);
989
990         return err;
991 }
992
993 int connman_element_create_property(struct connman_element *element,
994                                                 const char *name, int type)
995 {
996         return -EIO;
997 }
998
999 int connman_element_set_property(struct connman_element *element,
1000                                 enum connman_property_id id, const void *value)
1001 {
1002         switch (id) {
1003         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1004                 connman_element_lock(element);
1005                 g_free(element->ipv4.address);
1006                 element->ipv4.address = g_strdup(*((const char **) value));
1007                 connman_element_unlock(element);
1008                 break;
1009         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1010                 connman_element_lock(element);
1011                 g_free(element->ipv4.netmask);
1012                 element->ipv4.netmask = g_strdup(*((const char **) value));
1013                 connman_element_unlock(element);
1014                 break;
1015         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1016                 connman_element_lock(element);
1017                 g_free(element->ipv4.gateway);
1018                 element->ipv4.gateway = g_strdup(*((const char **) value));
1019                 connman_element_unlock(element);
1020                 break;
1021         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1022                 connman_element_lock(element);
1023                 g_free(element->ipv4.nameserver);
1024                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1025                 connman_element_unlock(element);
1026                 break;
1027         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1028                 connman_element_lock(element);
1029                 g_free(element->wifi.security);
1030                 element->wifi.security = g_strdup(*((const char **) value));
1031                 connman_element_unlock(element);
1032                 break;
1033         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1034                 connman_element_lock(element);
1035                 g_free(element->wifi.passphrase);
1036                 element->wifi.passphrase = g_strdup(*((const char **) value));
1037                 connman_element_unlock(element);
1038                 break;
1039         default:
1040                 return -EINVAL;
1041         }
1042
1043         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1044                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1045                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1046                                                         DBUS_TYPE_INVALID);
1047
1048         return 0;
1049 }
1050
1051 int connman_element_get_value(struct connman_element *element,
1052                                 enum connman_property_id id, void *value)
1053 {
1054         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1055                 return -EINVAL;
1056
1057         switch (id) {
1058         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1059                 if (element->ipv4.address == NULL)
1060                         return connman_element_get_value(element->parent,
1061                                                                 id, value);
1062                 connman_element_lock(element);
1063                 *((char **) value) = element->ipv4.address;
1064                 connman_element_unlock(element);
1065                 break;
1066         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1067                 if (element->ipv4.netmask == NULL)
1068                         return connman_element_get_value(element->parent,
1069                                                                 id, value);
1070                 connman_element_lock(element);
1071                 *((char **) value) = element->ipv4.netmask;
1072                 connman_element_unlock(element);
1073                 break;
1074         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1075                 if (element->ipv4.gateway == NULL)
1076                         return connman_element_get_value(element->parent,
1077                                                                 id, value);
1078                 connman_element_lock(element);
1079                 *((char **) value) = element->ipv4.gateway;
1080                 connman_element_unlock(element);
1081                 break;
1082         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1083                 if (element->ipv4.nameserver == NULL)
1084                         return connman_element_get_value(element->parent,
1085                                                                 id, value);
1086                 connman_element_lock(element);
1087                 *((char **) value) = element->ipv4.nameserver;
1088                 connman_element_unlock(element);
1089                 break;
1090         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1091                 if (element->wifi.security == NULL)
1092                         return connman_element_get_value(element->parent,
1093                                                                 id, value);
1094                 connman_element_lock(element);
1095                 *((char **) value) = element->wifi.security;
1096                 connman_element_unlock(element);
1097                 break;
1098         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1099                 if (element->wifi.passphrase == NULL)
1100                         return connman_element_get_value(element->parent,
1101                                                                 id, value);
1102                 connman_element_lock(element);
1103                 *((char **) value) = element->wifi.passphrase;
1104                 connman_element_unlock(element);
1105                 break;
1106         default:
1107                 return -EINVAL;
1108         }
1109
1110         return 0;
1111 }
1112
1113 gboolean connman_element_get_static_property(struct connman_element *element,
1114                                                 const char *name, void *value)
1115 {
1116         GSList *list;
1117         gboolean found = FALSE;
1118
1119         DBG("element %p name %s", element, element->name);
1120
1121         connman_element_lock(element);
1122
1123         for (list = element->properties; list; list = list->next) {
1124                 struct connman_property *property = list->data;
1125
1126                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1127                         continue;
1128
1129                 if (g_str_equal(property->name, name) == TRUE) {
1130                         *((char **) value) = property->value;
1131                         found = TRUE;
1132                         break;
1133                 }
1134         }
1135
1136         connman_element_unlock(element);
1137
1138         return found;
1139 }
1140
1141 gboolean connman_element_get_static_array_property(struct connman_element *element,
1142                                         const char *name, void *value, int *len)
1143 {
1144         GSList *list;
1145         gboolean found = FALSE;
1146
1147         DBG("element %p name %s", element, element->name);
1148
1149         connman_element_lock(element);
1150
1151         for (list = element->properties; list; list = list->next) {
1152                 struct connman_property *property = list->data;
1153
1154                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1155                         continue;
1156
1157                 if (g_str_equal(property->name, name) == TRUE) {
1158                         *((char **) value) = property->value;
1159                         *len = property->size;
1160                         found = TRUE;
1161                         break;
1162                 }
1163         }
1164
1165         connman_element_unlock(element);
1166
1167         return found;
1168 }
1169
1170 gboolean connman_element_match_static_property(struct connman_element *element,
1171                                         const char *name, const void *value)
1172 {
1173         GSList *list;
1174         gboolean result = FALSE;
1175
1176         DBG("element %p name %s", element, element->name);
1177
1178         connman_element_lock(element);
1179
1180         for (list = element->properties; list; list = list->next) {
1181                 struct connman_property *property = list->data;
1182
1183                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1184                         continue;
1185
1186                 if (g_str_equal(property->name, name) == FALSE)
1187                         continue;
1188
1189                 if (property->type == DBUS_TYPE_STRING)
1190                         result = g_str_equal(property->value,
1191                                                 *((const char **) value));
1192
1193                 if (result == TRUE)
1194                         break;
1195         }
1196
1197         connman_element_unlock(element);
1198
1199         return result;
1200 }
1201
1202 /**
1203  * connman_element_register:
1204  * @element: the element to register
1205  * @parent: the parent to register the element with
1206  *
1207  * Register an element with the core. It will be register under the given
1208  * parent of if %NULL is provided under the root element.
1209  *
1210  * Returns: %0 on success
1211  */
1212 int connman_element_register(struct connman_element *element,
1213                                         struct connman_element *parent)
1214 {
1215         DBG("element %p name %s parent %p", element, element->name, parent);
1216
1217         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1218                 if (g_pattern_match_simple(device_filter,
1219                                                 element->name) == FALSE) {
1220                         DBG("ignoring %s device", element->name);
1221                         return -EPERM;
1222                 }
1223         }
1224
1225         if (connman_element_ref(element) == NULL)
1226                 return -EINVAL;
1227
1228         connman_element_lock(element);
1229
1230         if (element->name == NULL) {
1231                 element->name = g_strdup(type2string(element->type));
1232                 if (element->name == NULL) {
1233                         connman_element_unlock(element);
1234                         return -EINVAL;
1235                 }
1236         }
1237
1238         element->parent = parent;
1239
1240         connman_element_unlock(element);
1241
1242         if (thread_register != NULL)
1243                 g_thread_pool_push(thread_register, element, NULL);
1244
1245         return 0;
1246 }
1247
1248 void connman_element_unregister(struct connman_element *element)
1249 {
1250         DBG("element %p name %s", element, element->name);
1251
1252         if (thread_unregister != NULL)
1253                 g_thread_pool_push(thread_unregister, element, NULL);
1254 }
1255
1256 void connman_element_unregister_children(struct connman_element *element)
1257 {
1258         DBG("element %p name %s", element, element->name);
1259
1260         if (thread_unregister_children != NULL)
1261                 g_thread_pool_push(thread_unregister_children, element, NULL);
1262 }
1263
1264 static gboolean update_element(GNode *node, gpointer user_data)
1265 {
1266         struct connman_element *element = node->data;
1267
1268         DBG("element %p name %s", element, element->name);
1269
1270         if (element->driver && element->driver->update)
1271                 element->driver->update(element);
1272
1273         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1274                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1275                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1276                                                         DBUS_TYPE_INVALID);
1277
1278         return FALSE;
1279 }
1280
1281 void connman_element_update(struct connman_element *element)
1282 {
1283         GNode *node;
1284
1285         DBG("element %p name %s", element, element->name);
1286
1287         g_static_rw_lock_reader_lock(&element_lock);
1288
1289         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1290
1291         if (node != NULL)
1292                 g_node_traverse(node, G_PRE_ORDER,
1293                                 G_TRAVERSE_ALL, -1, update_element, NULL);
1294
1295         g_static_rw_lock_reader_unlock(&element_lock);
1296 }
1297
1298 int connman_element_set_enabled(struct connman_element *element,
1299                                                         gboolean enabled)
1300 {
1301         if (element->enabled == enabled)
1302                 return 0;
1303
1304         element->enabled = enabled;
1305
1306         connman_element_update(element);
1307
1308         return 0;
1309 }
1310
1311 static void register_element(gpointer data, gpointer user_data)
1312 {
1313         struct connman_element *element = data;
1314         const gchar *basepath;
1315         GSList *list;
1316         GNode *node;
1317
1318         g_static_rw_lock_writer_lock(&element_lock);
1319
1320         connman_element_lock(element);
1321
1322         if (element->parent) {
1323                 node = g_node_find(element_root, G_PRE_ORDER,
1324                                         G_TRAVERSE_ALL, element->parent);
1325                 basepath = element->parent->path;
1326
1327                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1328                         element->subtype = element->parent->subtype;
1329         } else {
1330                 element->parent = element_root->data;
1331
1332                 node = element_root;
1333                 basepath = "";
1334         }
1335
1336         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1337
1338         set_reference_properties(element);
1339
1340         connman_element_unlock(element);
1341
1342         DBG("element %p path %s", element, element->path);
1343
1344         __connman_element_load(element);
1345
1346         g_node_append_data(node, element);
1347
1348         if (g_dbus_register_interface(connection, element->path,
1349                                         CONNMAN_ELEMENT_INTERFACE,
1350                                         element_methods, element_signals,
1351                                         NULL, element, NULL) == FALSE)
1352                 connman_error("Failed to register %s element", element->path);
1353
1354         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1355                 if (g_dbus_register_interface(connection, element->path,
1356                                         CONNMAN_DEVICE_INTERFACE,
1357                                         device_methods, element_signals,
1358                                         NULL, element, NULL) == FALSE)
1359                         connman_error("Failed to register %s device",
1360                                                                 element->path);
1361         }
1362
1363         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1364                 if (g_dbus_register_interface(connection, element->path,
1365                                         CONNMAN_NETWORK_INTERFACE,
1366                                         network_methods, element_signals,
1367                                         NULL, element, NULL) == FALSE)
1368                         connman_error("Failed to register %s network",
1369                                                                 element->path);
1370         }
1371
1372         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1373                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
1374                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1375                                                         DBUS_TYPE_INVALID);
1376
1377         g_static_rw_lock_writer_unlock(&element_lock);
1378
1379         __connman_element_store(element);
1380
1381         g_static_rw_lock_writer_lock(&element_lock);
1382
1383         for (list = driver_list; list; list = list->next) {
1384                 struct connman_driver *driver = list->data;
1385
1386                 if (match_driver(element, driver) == FALSE)
1387                         continue;
1388
1389                 DBG("driver %p name %s", driver, driver->name);
1390
1391                 if (driver->probe(element) == 0) {
1392                         connman_element_lock(element);
1393                         element->driver = driver;
1394                         connman_element_unlock(element);
1395                         break;
1396                 }
1397         }
1398
1399         g_static_rw_lock_writer_unlock(&element_lock);
1400 }
1401
1402 static gboolean remove_element(GNode *node, gpointer user_data)
1403 {
1404         struct connman_element *element = node->data;
1405         struct connman_element *root = user_data;
1406
1407         DBG("element %p name %s", element, element->name);
1408
1409         if (element == root)
1410                 return FALSE;
1411
1412         if (element->driver) {
1413                 if (element->driver->remove)
1414                         element->driver->remove(element);
1415
1416                 connman_element_lock(element);
1417                 element->driver = NULL;
1418                 connman_element_unlock(element);
1419         }
1420
1421         if (node != NULL) {
1422                 g_node_unlink(node);
1423                 g_node_destroy(node);
1424         }
1425
1426         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1427                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
1428                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1429                                                         DBUS_TYPE_INVALID);
1430
1431         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK)
1432                 g_dbus_unregister_interface(connection, element->path,
1433                                                 CONNMAN_NETWORK_INTERFACE);
1434
1435         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
1436                 g_dbus_unregister_interface(connection, element->path,
1437                                                 CONNMAN_DEVICE_INTERFACE);
1438
1439         g_dbus_unregister_interface(connection, element->path,
1440                                                 CONNMAN_ELEMENT_INTERFACE);
1441
1442         connman_element_unref(element);
1443
1444         return FALSE;
1445 }
1446
1447 static void unregister_element(gpointer data, gpointer user_data)
1448 {
1449         struct connman_element *element = data;
1450         GNode *node;
1451
1452         DBG("element %p name %s", element, element->name);
1453
1454         g_static_rw_lock_writer_lock(&element_lock);
1455
1456         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1457
1458         if (node != NULL)
1459                 g_node_traverse(node, G_POST_ORDER,
1460                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1461
1462         g_static_rw_lock_writer_unlock(&element_lock);
1463 }
1464
1465 static void unregister_children(gpointer data, gpointer user_data)
1466 {
1467         struct connman_element *element = data;
1468         GNode *node;
1469
1470         DBG("element %p name %s", element, element->name);
1471
1472         g_static_rw_lock_writer_lock(&element_lock);
1473
1474         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1475
1476         if (node != NULL)
1477                 g_node_traverse(node, G_POST_ORDER,
1478                                 G_TRAVERSE_ALL, -1, remove_element, element);
1479
1480         g_static_rw_lock_writer_unlock(&element_lock);
1481 }
1482
1483 int __connman_element_init(DBusConnection *conn, const char *device)
1484 {
1485         struct connman_element *element;
1486
1487         DBG("conn %p", conn);
1488
1489         connection = dbus_connection_ref(conn);
1490         if (connection == NULL)
1491                 return -EIO;
1492
1493         device_filter = g_strdup(device);
1494
1495         g_static_rw_lock_writer_lock(&element_lock);
1496
1497         element = connman_element_create("root");
1498
1499         element->path = g_strdup("/");
1500         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1501
1502         create_default_properties(element);
1503
1504         element_root = g_node_new(element);
1505
1506         g_static_rw_lock_writer_unlock(&element_lock);
1507
1508         thread_register = g_thread_pool_new(register_element,
1509                                                         NULL, 1, FALSE, NULL);
1510         thread_unregister = g_thread_pool_new(unregister_element,
1511                                                         NULL, 1, FALSE, NULL);
1512         thread_unregister_children = g_thread_pool_new(unregister_children,
1513                                                         NULL, 1, FALSE, NULL);
1514
1515         __connman_device_init();
1516
1517         return 0;
1518 }
1519
1520 static gboolean free_driver(GNode *node, gpointer data)
1521 {
1522         struct connman_element *element = node->data;
1523
1524         DBG("element %p name %s", element, element->name);
1525
1526         if (element->driver) {
1527                 if (element->driver->remove)
1528                         element->driver->remove(element);
1529
1530                 connman_element_lock(element);
1531                 element->driver = NULL;
1532                 connman_element_unlock(element);
1533         }
1534
1535         return FALSE;
1536 }
1537
1538 static gboolean free_node(GNode *node, gpointer data)
1539 {
1540         struct connman_element *element = node->data;
1541
1542         DBG("element %p name %s", element, element->name);
1543
1544         if (g_node_depth(node) > 1)
1545                 g_thread_pool_push(thread_unregister, element, NULL);
1546
1547         return FALSE;
1548 }
1549
1550 void __connman_element_cleanup(void)
1551 {
1552         DBG("");
1553
1554         __connman_device_cleanup();
1555
1556         g_thread_pool_free(thread_register, TRUE, TRUE);
1557         thread_register = NULL;
1558
1559         g_static_rw_lock_writer_lock(&element_lock);
1560         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1561                                                         free_driver, NULL);
1562         g_static_rw_lock_writer_unlock(&element_lock);
1563
1564         g_static_rw_lock_writer_lock(&element_lock);
1565         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1566                                                         free_node, NULL);
1567         g_static_rw_lock_writer_unlock(&element_lock);
1568
1569         g_thread_pool_free(thread_unregister, FALSE, TRUE);
1570         thread_unregister = NULL;
1571
1572         g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
1573         thread_unregister_children = NULL;
1574
1575         g_static_rw_lock_writer_lock(&element_lock);
1576         g_node_destroy(element_root);
1577         element_root = NULL;
1578         g_static_rw_lock_writer_unlock(&element_lock);
1579
1580         g_free(device_filter);
1581
1582         dbus_connection_unref(connection);
1583 }