Provide connection element and its interface
[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_CONNECTION:
123                 return "connection";
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 *get_connection_properties(DBusConnection *conn,
323                                         DBusMessage *msg, void *data)
324 {
325         struct connman_element *element = data;
326         DBusMessage *reply;
327         DBusMessageIter array, dict;
328
329         DBG("conn %p", conn);
330
331         reply = dbus_message_new_method_return(msg);
332         if (reply == NULL)
333                 return NULL;
334
335         dbus_message_iter_init_append(reply, &array);
336
337         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
338                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
339                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
340                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
341
342         add_common_properties(element, &dict);
343
344         dbus_message_iter_close_container(&array, &dict);
345
346         return reply;
347 }
348
349 static DBusMessage *set_property(DBusConnection *conn,
350                                         DBusMessage *msg, void *data)
351 {
352         struct connman_element *element = data;
353         DBusMessageIter iter;
354         DBusMessageIter value;
355         const char *name;
356         GSList *list;
357
358         DBG("conn %p", conn);
359
360         if (dbus_message_iter_init(msg, &iter) == FALSE)
361                 return __connman_error_invalid_arguments(msg);
362
363         dbus_message_iter_get_basic(&iter, &name);
364         dbus_message_iter_next(&iter);
365         dbus_message_iter_recurse(&iter, &value);
366
367         if (__connman_security_check_privileges(msg) < 0)
368                 return __connman_error_permission_denied(msg);
369
370         connman_element_lock(element);
371
372         for (list = element->properties; list; list = list->next) {
373                 struct connman_property *property = list->data;
374                 const char *str;
375
376                 if (g_str_equal(property->name, name) == FALSE)
377                         continue;
378
379                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
380                         continue;
381
382                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
383
384                 if (property->type == DBUS_TYPE_STRING) {
385                         dbus_message_iter_get_basic(&value, &str);
386                         g_free(property->value);
387                         property->value = g_strdup(str);
388                 } else
389                         property->value = NULL;
390         }
391
392         connman_element_unlock(element);
393
394         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
395 }
396
397 static DBusMessage *clear_property(DBusConnection *conn,
398                                         DBusMessage *msg, void *data)
399 {
400         struct connman_element *element = data;
401         const char *name;
402         GSList *list;
403
404         DBG("conn %p", conn);
405
406         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
407                                                 DBUS_TYPE_INVALID) == FALSE)
408                 return __connman_error_invalid_arguments(msg);
409
410         if (__connman_security_check_privileges(msg) < 0)
411                 return __connman_error_permission_denied(msg);
412
413         connman_element_lock(element);
414
415         for (list = element->properties; list; list = list->next) {
416                 struct connman_property *property = list->data;
417
418                 if (g_str_equal(property->name, name) == FALSE)
419                         continue;
420
421                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
422                         continue;
423
424                 if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)
425                         continue;
426
427                 property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE;
428
429                 if (property->type == DBUS_TYPE_STRING)
430                         g_free(property->value);
431
432                 property->value = NULL;
433         }
434
435         connman_element_unlock(element);
436
437         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
438 }
439
440 static DBusMessage *do_update(DBusConnection *conn,
441                                         DBusMessage *msg, void *data)
442 {
443         struct connman_element *element = data;
444
445         DBG("conn %p", conn);
446
447         if (element->enabled == FALSE)
448                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
449
450         if (element->driver && element->driver->update) {
451                 DBG("Calling update callback");
452                 element->driver->update(element);
453         }
454
455         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
456 }
457
458 static DBusMessage *do_enable(DBusConnection *conn,
459                                         DBusMessage *msg, void *data)
460 {
461         struct connman_element *element = data;
462
463         DBG("conn %p", conn);
464
465         if (element->enabled == TRUE)
466                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
467
468         if (element->driver && element->driver->enable) {
469                 DBG("Calling enable callback");
470                 if (element->driver->enable(element) < 0)
471                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
472         }
473
474         element->enabled = TRUE;
475
476         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
477                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
478                                 DBUS_TYPE_OBJECT_PATH, &element->path,
479                                                         DBUS_TYPE_INVALID);
480
481         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
482 }
483
484 static DBusMessage *do_disable(DBusConnection *conn,
485                                         DBusMessage *msg, void *data)
486 {
487         struct connman_element *element = data;
488
489         DBG("conn %p", conn);
490
491         if (element->enabled == FALSE)
492                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
493
494         if (element->driver && element->driver->disable) {
495                 DBG("Calling disable callback");
496                 if (element->driver->disable(element) < 0)
497                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
498         }
499
500         element->enabled = FALSE;
501
502         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
503                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
504                                 DBUS_TYPE_OBJECT_PATH, &element->path,
505                                                         DBUS_TYPE_INVALID);
506
507         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
508 }
509
510 static GDBusMethodTable element_methods[] = {
511         { "GetProperties", "",   "a{sv}", get_properties },
512         { "SetProperty",   "sv", "",      set_property   },
513         { "ClearProperty", "s",  "",      clear_property },
514         { "Update",        "",   "",      do_update      },
515         { "Enable",        "",   "",      do_enable      },
516         { "Disable",       "",   "",      do_disable     },
517         { },
518 };
519
520 static GDBusSignalTable element_signals[] = {
521         { "PropertyChanged", "sv" },
522         { },
523 };
524
525 static GDBusMethodTable device_methods[] = {
526         { "GetProperties", "",   "a{sv}", get_device_properties },
527         { },
528 };
529
530 static GDBusMethodTable network_methods[] = {
531         { "GetProperties", "",   "a{sv}", get_network_properties },
532         { },
533 };
534
535 static GDBusMethodTable connection_methods[] = {
536         { "GetProperties", "",   "a{sv}", get_connection_properties },
537         { },
538 };
539
540 struct append_filter {
541         enum connman_element_type type;
542         DBusMessageIter *iter;
543 };
544
545 static gboolean append_path(GNode *node, gpointer data)
546 {
547         struct connman_element *element = node->data;
548         struct append_filter *filter = data;
549
550         DBG("element %p name %s", element, element->name);
551
552         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
553                 return FALSE;
554
555         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
556                                         filter->type != element->type)
557                 return FALSE;
558
559         dbus_message_iter_append_basic(filter->iter,
560                                 DBUS_TYPE_OBJECT_PATH, &element->path);
561
562         return FALSE;
563 }
564
565 void __connman_element_list(enum connman_element_type type,
566                                                 DBusMessageIter *iter)
567 {
568         struct append_filter filter = { type, iter };
569
570         DBG("");
571
572         g_static_rw_lock_reader_lock(&element_lock);
573         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
574                                                         append_path, &filter);
575         g_static_rw_lock_reader_unlock(&element_lock);
576 }
577
578 static gint compare_priority(gconstpointer a, gconstpointer b)
579 {
580         const struct connman_driver *driver1 = a;
581         const struct connman_driver *driver2 = b;
582
583         return driver2->priority - driver1->priority;
584 }
585
586 static gboolean match_driver(struct connman_element *element,
587                                         struct connman_driver *driver)
588 {
589         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
590                 return FALSE;
591
592         if (element->type != driver->type &&
593                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
594                 return FALSE;
595
596         if (element->subtype == driver->subtype ||
597                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
598                 return TRUE;
599
600         return FALSE;
601 }
602
603 static gboolean probe_driver(GNode *node, gpointer data)
604 {
605         struct connman_element *element = node->data;
606         struct connman_driver *driver = data;
607
608         DBG("element %p name %s", element, element->name);
609
610         if (!element->driver && match_driver(element, driver) == TRUE) {
611                 if (driver->probe(element) < 0)
612                         return FALSE;
613
614                 connman_element_lock(element);
615                 element->driver = driver;
616                 connman_element_unlock(element);
617         }
618
619         return FALSE;
620 }
621
622 void __connman_driver_rescan(struct connman_driver *driver)
623 {
624         DBG("driver %p name %s", driver, driver->name);
625
626         if (!driver->probe)
627                 return;
628
629         g_static_rw_lock_writer_lock(&element_lock);
630
631         if (element_root != NULL)
632                 g_node_traverse(element_root, G_PRE_ORDER,
633                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
634
635         g_static_rw_lock_writer_unlock(&element_lock);
636 }
637
638 /**
639  * connman_driver_register:
640  * @driver: driver definition
641  *
642  * Register a new driver
643  *
644  * Returns: %0 on success
645  */
646 int connman_driver_register(struct connman_driver *driver)
647 {
648         DBG("driver %p name %s", driver, driver->name);
649
650         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
651                 return -EINVAL;
652
653         if (!driver->probe)
654                 return -EINVAL;
655
656         g_static_rw_lock_writer_lock(&element_lock);
657
658         driver_list = g_slist_insert_sorted(driver_list, driver,
659                                                         compare_priority);
660
661         if (element_root != NULL)
662                 g_node_traverse(element_root, G_PRE_ORDER,
663                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
664
665         g_static_rw_lock_writer_unlock(&element_lock);
666
667         return 0;
668 }
669
670 static gboolean remove_driver(GNode *node, gpointer data)
671 {
672         struct connman_element *element = node->data;
673         struct connman_driver *driver = data;
674
675         DBG("element %p name %s", element, element->name);
676
677         if (element->driver == driver) {
678                 if (driver->remove)
679                         driver->remove(element);
680
681                 connman_element_lock(element);
682                 element->driver = NULL;
683                 connman_element_unlock(element);
684         }
685
686         return FALSE;
687 }
688
689 /**
690  * connman_driver_unregister:
691  * @driver: driver definition
692  *
693  * Remove a previously registered driver
694  */
695 void connman_driver_unregister(struct connman_driver *driver)
696 {
697         DBG("driver %p name %s", driver, driver->name);
698
699         g_static_rw_lock_writer_lock(&element_lock);
700
701         driver_list = g_slist_remove(driver_list, driver);
702
703         if (element_root != NULL)
704                 g_node_traverse(element_root, G_POST_ORDER,
705                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
706
707         g_static_rw_lock_writer_unlock(&element_lock);
708 }
709
710 /**
711  * connman_element_create:
712  * @name: element name
713  *
714  * Allocate a new element and assign the given #name to it. If the name
715  * is #NULL, it will be later on created based on the element type.
716  *
717  * Returns: a newly-allocated #connman_element structure
718  */
719 struct connman_element *connman_element_create(const char *name)
720 {
721         struct connman_element *element;
722
723         element = g_try_new0(struct connman_element, 1);
724         if (element == NULL)
725                 return NULL;
726
727         DBG("element %p", element);
728
729         element->refcount = 1;
730
731         g_static_mutex_init(&element->mutex);
732
733         element->name    = g_strdup(name);
734         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
735         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
736         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
737         element->index   = -1;
738         element->enabled = FALSE;
739
740         return element;
741 }
742
743 struct connman_element *connman_element_ref(struct connman_element *element)
744 {
745         DBG("element %p name %s refcount %d", element, element->name,
746                                 g_atomic_int_get(&element->refcount) + 1);
747
748         g_atomic_int_inc(&element->refcount);
749
750         return element;
751 }
752
753 static void free_properties(struct connman_element *element)
754 {
755         GSList *list;
756
757         DBG("element %p name %s", element, element->name);
758
759         connman_element_lock(element);
760
761         for (list = element->properties; list; list = list->next) {
762                 struct connman_property *property = list->data;
763
764                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) {
765                         if (property->type == DBUS_TYPE_STRING)
766                                 g_free(property->value);
767                         if (property->type == DBUS_TYPE_ARRAY &&
768                                         property->subtype == DBUS_TYPE_BYTE)
769                                 g_free(property->value);
770                 }
771
772                 g_free(property);
773         }
774
775         g_slist_free(element->properties);
776
777         element->properties = NULL;
778
779         connman_element_unlock(element);
780 }
781
782 void connman_element_unref(struct connman_element *element)
783 {
784         DBG("element %p name %s refcount %d", element, element->name,
785                                 g_atomic_int_get(&element->refcount) - 1);
786
787         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
788                 free_properties(element);
789                 g_free(element->ipv4.address);
790                 g_free(element->ipv4.netmask);
791                 g_free(element->ipv4.gateway);
792                 g_free(element->ipv4.network);
793                 g_free(element->ipv4.broadcast);
794                 g_free(element->ipv4.nameserver);
795                 g_free(element->path);
796                 g_free(element->name);
797                 g_free(element);
798         }
799 }
800
801 int connman_element_add_static_property(struct connman_element *element,
802                                 const char *name, int type, const void *value)
803 {
804         struct connman_property *property;
805
806         DBG("element %p name %s", element, element->name);
807
808         if (type != DBUS_TYPE_STRING)
809                 return -EINVAL;
810
811         property = g_try_new0(struct connman_property, 1);
812         if (property == NULL)
813                 return -ENOMEM;
814
815         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
816         property->id    = CONNMAN_PROPERTY_ID_INVALID;
817         property->name  = g_strdup(name);
818         property->type  = type;
819
820         DBG("name %s type %d value %p", name, type, value);
821
822         switch (type) {
823         case DBUS_TYPE_STRING:
824                 property->value = g_strdup(*((const char **) value));
825                 break;
826         }
827
828         connman_element_lock(element);
829         element->properties = g_slist_append(element->properties, property);
830         connman_element_unlock(element);
831
832         return 0;
833 }
834
835 int connman_element_add_static_array_property(struct connman_element *element,
836                         const char *name, int type, const void *value, int len)
837 {
838         struct connman_property *property;
839
840         DBG("element %p name %s", element, element->name);
841
842         if (type != DBUS_TYPE_BYTE)
843                 return -EINVAL;
844
845         property = g_try_new0(struct connman_property, 1);
846         if (property == NULL)
847                 return -ENOMEM;
848
849         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
850         property->id      = CONNMAN_PROPERTY_ID_INVALID;
851         property->name    = g_strdup(name);
852         property->type    = DBUS_TYPE_ARRAY;
853         property->subtype = type;
854
855         DBG("name %s type %d value %p", name, type, value);
856
857         switch (type) {
858         case DBUS_TYPE_BYTE:
859                 property->value = g_try_malloc(len);
860                 if (property->value != NULL) {
861                         memcpy(property->value,
862                                 *((const unsigned char **) value), len);
863                         property->size = len;
864                 }
865                 break;
866         }
867
868         connman_element_lock(element);
869         element->properties = g_slist_append(element->properties, property);
870         connman_element_unlock(element);
871
872         return 0;
873 }
874
875 static void *get_reference_value(struct connman_element *element,
876                                                 enum connman_property_id id)
877 {
878         GSList *list;
879
880         DBG("element %p name %s", element, element->name);
881
882         for (list = element->properties; list; list = list->next) {
883                 struct connman_property *property = list->data;
884
885                 if (property->id != id)
886                         continue;
887
888                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
889                         return property->value;
890         }
891
892         if (element->parent == NULL)
893                 return NULL;
894
895         return get_reference_value(element->parent, id);
896 }
897
898 static void set_reference_properties(struct connman_element *element)
899 {
900         GSList *list;
901
902         DBG("element %p name %s", element, element->name);
903
904         for (list = element->properties; list; list = list->next) {
905                 struct connman_property *property = list->data;
906
907                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
908                         continue;
909
910                 property->value = get_reference_value(element->parent,
911                                                                 property->id);
912         }
913 }
914
915 static struct connman_property *create_property(struct connman_element *element,
916                                                 enum connman_property_id id)
917 {
918         struct connman_property *property;
919         GSList *list;
920
921         DBG("element %p name %s", element, element->name);
922
923         connman_element_lock(element);
924
925         for (list = element->properties; list; list = list->next) {
926                 property = list->data;
927
928                 if (property->id == id)
929                         goto unlock;
930         }
931
932         property = g_try_new0(struct connman_property, 1);
933         if (property == NULL)
934                 goto unlock;
935
936         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
937         property->id    = id;
938         property->name  = g_strdup(propid2name(id));
939         property->type  = propid2type(id);
940
941         if (property->name == NULL) {
942                 g_free(property);
943                 property = NULL;
944                 goto unlock;
945         }
946
947         element->properties = g_slist_append(element->properties, property);
948
949 unlock:
950         connman_element_unlock(element);
951
952         return property;
953 }
954
955 static void create_default_properties(struct connman_element *element)
956 {
957         struct connman_property *property;
958         int i;
959
960         DBG("element %p name %s", element, element->name);
961
962         for (i = 0; propid_table[i].name; i++) {
963                 DBG("property %s", propid_table[i].name);
964
965                 property = create_property(element, propid_table[i].id);
966
967                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
968
969                 if (propid_table[i].type != DBUS_TYPE_STRING)
970                         continue;
971
972                 if (propid_table[i].value)
973                         property->value = g_strdup(propid_table[i].value);
974                 else
975                         property->value = g_strdup("");
976         }
977 }
978
979 static int define_properties_valist(struct connman_element *element,
980                                                                 va_list args)
981 {
982         enum connman_property_id id;
983
984         DBG("element %p name %s", element, element->name);
985
986         id = va_arg(args, enum connman_property_id);
987
988         while (id != CONNMAN_PROPERTY_ID_INVALID) {
989
990                 DBG("property %d", id);
991
992                 create_property(element, id);
993
994                 id = va_arg(args, enum connman_property_id);
995         }
996
997         return 0;
998 }
999
1000 /**
1001  * connman_element_define_properties:
1002  * @element: an element
1003  * @varargs: list of property identifiers
1004  *
1005  * Define the valid properties for an element.
1006  *
1007  * Returns: %0 on success
1008  */
1009 int connman_element_define_properties(struct connman_element *element, ...)
1010 {
1011         va_list args;
1012         int err;
1013
1014         DBG("element %p name %s", element, element->name);
1015
1016         va_start(args, element);
1017
1018         err = define_properties_valist(element, args);
1019
1020         va_end(args);
1021
1022         return err;
1023 }
1024
1025 int connman_element_create_property(struct connman_element *element,
1026                                                 const char *name, int type)
1027 {
1028         return -EIO;
1029 }
1030
1031 int connman_element_set_property(struct connman_element *element,
1032                                 enum connman_property_id id, const void *value)
1033 {
1034         switch (id) {
1035         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1036                 connman_element_lock(element);
1037                 g_free(element->ipv4.address);
1038                 element->ipv4.address = g_strdup(*((const char **) value));
1039                 connman_element_unlock(element);
1040                 break;
1041         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1042                 connman_element_lock(element);
1043                 g_free(element->ipv4.netmask);
1044                 element->ipv4.netmask = g_strdup(*((const char **) value));
1045                 connman_element_unlock(element);
1046                 break;
1047         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1048                 connman_element_lock(element);
1049                 g_free(element->ipv4.gateway);
1050                 element->ipv4.gateway = g_strdup(*((const char **) value));
1051                 connman_element_unlock(element);
1052                 break;
1053         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1054                 connman_element_lock(element);
1055                 g_free(element->ipv4.nameserver);
1056                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1057                 connman_element_unlock(element);
1058                 break;
1059         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1060                 connman_element_lock(element);
1061                 g_free(element->wifi.security);
1062                 element->wifi.security = g_strdup(*((const char **) value));
1063                 connman_element_unlock(element);
1064                 break;
1065         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1066                 connman_element_lock(element);
1067                 g_free(element->wifi.passphrase);
1068                 element->wifi.passphrase = g_strdup(*((const char **) value));
1069                 connman_element_unlock(element);
1070                 break;
1071         default:
1072                 return -EINVAL;
1073         }
1074
1075         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1076                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1077                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1078                                                         DBUS_TYPE_INVALID);
1079
1080         return 0;
1081 }
1082
1083 int connman_element_get_value(struct connman_element *element,
1084                                 enum connman_property_id id, void *value)
1085 {
1086         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1087                 return -EINVAL;
1088
1089         switch (id) {
1090         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1091                 if (element->ipv4.address == NULL)
1092                         return connman_element_get_value(element->parent,
1093                                                                 id, value);
1094                 connman_element_lock(element);
1095                 *((char **) value) = element->ipv4.address;
1096                 connman_element_unlock(element);
1097                 break;
1098         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1099                 if (element->ipv4.netmask == NULL)
1100                         return connman_element_get_value(element->parent,
1101                                                                 id, value);
1102                 connman_element_lock(element);
1103                 *((char **) value) = element->ipv4.netmask;
1104                 connman_element_unlock(element);
1105                 break;
1106         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1107                 if (element->ipv4.gateway == NULL)
1108                         return connman_element_get_value(element->parent,
1109                                                                 id, value);
1110                 connman_element_lock(element);
1111                 *((char **) value) = element->ipv4.gateway;
1112                 connman_element_unlock(element);
1113                 break;
1114         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1115                 if (element->ipv4.nameserver == NULL)
1116                         return connman_element_get_value(element->parent,
1117                                                                 id, value);
1118                 connman_element_lock(element);
1119                 *((char **) value) = element->ipv4.nameserver;
1120                 connman_element_unlock(element);
1121                 break;
1122         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1123                 if (element->wifi.security == NULL)
1124                         return connman_element_get_value(element->parent,
1125                                                                 id, value);
1126                 connman_element_lock(element);
1127                 *((char **) value) = element->wifi.security;
1128                 connman_element_unlock(element);
1129                 break;
1130         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1131                 if (element->wifi.passphrase == NULL)
1132                         return connman_element_get_value(element->parent,
1133                                                                 id, value);
1134                 connman_element_lock(element);
1135                 *((char **) value) = element->wifi.passphrase;
1136                 connman_element_unlock(element);
1137                 break;
1138         default:
1139                 return -EINVAL;
1140         }
1141
1142         return 0;
1143 }
1144
1145 gboolean connman_element_get_static_property(struct connman_element *element,
1146                                                 const char *name, void *value)
1147 {
1148         GSList *list;
1149         gboolean found = FALSE;
1150
1151         DBG("element %p name %s", element, element->name);
1152
1153         connman_element_lock(element);
1154
1155         for (list = element->properties; list; list = list->next) {
1156                 struct connman_property *property = list->data;
1157
1158                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1159                         continue;
1160
1161                 if (g_str_equal(property->name, name) == TRUE) {
1162                         *((char **) value) = property->value;
1163                         found = TRUE;
1164                         break;
1165                 }
1166         }
1167
1168         connman_element_unlock(element);
1169
1170         return found;
1171 }
1172
1173 gboolean connman_element_get_static_array_property(struct connman_element *element,
1174                                         const char *name, void *value, int *len)
1175 {
1176         GSList *list;
1177         gboolean found = FALSE;
1178
1179         DBG("element %p name %s", element, element->name);
1180
1181         connman_element_lock(element);
1182
1183         for (list = element->properties; list; list = list->next) {
1184                 struct connman_property *property = list->data;
1185
1186                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1187                         continue;
1188
1189                 if (g_str_equal(property->name, name) == TRUE) {
1190                         *((char **) value) = property->value;
1191                         *len = property->size;
1192                         found = TRUE;
1193                         break;
1194                 }
1195         }
1196
1197         connman_element_unlock(element);
1198
1199         return found;
1200 }
1201
1202 gboolean connman_element_match_static_property(struct connman_element *element,
1203                                         const char *name, const void *value)
1204 {
1205         GSList *list;
1206         gboolean result = FALSE;
1207
1208         DBG("element %p name %s", element, element->name);
1209
1210         connman_element_lock(element);
1211
1212         for (list = element->properties; list; list = list->next) {
1213                 struct connman_property *property = list->data;
1214
1215                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1216                         continue;
1217
1218                 if (g_str_equal(property->name, name) == FALSE)
1219                         continue;
1220
1221                 if (property->type == DBUS_TYPE_STRING)
1222                         result = g_str_equal(property->value,
1223                                                 *((const char **) value));
1224
1225                 if (result == TRUE)
1226                         break;
1227         }
1228
1229         connman_element_unlock(element);
1230
1231         return result;
1232 }
1233
1234 /**
1235  * connman_element_register:
1236  * @element: the element to register
1237  * @parent: the parent to register the element with
1238  *
1239  * Register an element with the core. It will be register under the given
1240  * parent of if %NULL is provided under the root element.
1241  *
1242  * Returns: %0 on success
1243  */
1244 int connman_element_register(struct connman_element *element,
1245                                         struct connman_element *parent)
1246 {
1247         DBG("element %p name %s parent %p", element, element->name, parent);
1248
1249         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1250                 if (g_pattern_match_simple(device_filter,
1251                                                 element->name) == FALSE) {
1252                         DBG("ignoring %s device", element->name);
1253                         return -EPERM;
1254                 }
1255         }
1256
1257         if (connman_element_ref(element) == NULL)
1258                 return -EINVAL;
1259
1260         connman_element_lock(element);
1261
1262         if (element->name == NULL) {
1263                 element->name = g_strdup(type2string(element->type));
1264                 if (element->name == NULL) {
1265                         connman_element_unlock(element);
1266                         return -EINVAL;
1267                 }
1268         }
1269
1270         element->parent = parent;
1271
1272         connman_element_unlock(element);
1273
1274         if (thread_register != NULL)
1275                 g_thread_pool_push(thread_register, element, NULL);
1276
1277         return 0;
1278 }
1279
1280 void connman_element_unregister(struct connman_element *element)
1281 {
1282         DBG("element %p name %s", element, element->name);
1283
1284         if (thread_unregister != NULL)
1285                 g_thread_pool_push(thread_unregister, element, NULL);
1286 }
1287
1288 void connman_element_unregister_children(struct connman_element *element)
1289 {
1290         DBG("element %p name %s", element, element->name);
1291
1292         if (thread_unregister_children != NULL)
1293                 g_thread_pool_push(thread_unregister_children, element, NULL);
1294 }
1295
1296 static gboolean update_element(GNode *node, gpointer user_data)
1297 {
1298         struct connman_element *element = node->data;
1299
1300         DBG("element %p name %s", element, element->name);
1301
1302         if (element->driver && element->driver->update)
1303                 element->driver->update(element);
1304
1305         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1306                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1307                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1308                                                         DBUS_TYPE_INVALID);
1309
1310         return FALSE;
1311 }
1312
1313 void connman_element_update(struct connman_element *element)
1314 {
1315         GNode *node;
1316
1317         DBG("element %p name %s", element, element->name);
1318
1319         g_static_rw_lock_reader_lock(&element_lock);
1320
1321         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1322
1323         if (node != NULL)
1324                 g_node_traverse(node, G_PRE_ORDER,
1325                                 G_TRAVERSE_ALL, -1, update_element, NULL);
1326
1327         g_static_rw_lock_reader_unlock(&element_lock);
1328 }
1329
1330 int connman_element_set_enabled(struct connman_element *element,
1331                                                         gboolean enabled)
1332 {
1333         if (element->enabled == enabled)
1334                 return 0;
1335
1336         element->enabled = enabled;
1337
1338         connman_element_update(element);
1339
1340         return 0;
1341 }
1342
1343 static void register_element(gpointer data, gpointer user_data)
1344 {
1345         struct connman_element *element = data;
1346         const gchar *basepath;
1347         GSList *list;
1348         GNode *node;
1349
1350         g_static_rw_lock_writer_lock(&element_lock);
1351
1352         connman_element_lock(element);
1353
1354         if (element->parent) {
1355                 node = g_node_find(element_root, G_PRE_ORDER,
1356                                         G_TRAVERSE_ALL, element->parent);
1357                 basepath = element->parent->path;
1358
1359                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1360                         element->subtype = element->parent->subtype;
1361         } else {
1362                 element->parent = element_root->data;
1363
1364                 node = element_root;
1365                 basepath = "";
1366         }
1367
1368         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1369
1370         set_reference_properties(element);
1371
1372         connman_element_unlock(element);
1373
1374         DBG("element %p path %s", element, element->path);
1375
1376         __connman_element_load(element);
1377
1378         g_node_append_data(node, element);
1379
1380         if (g_dbus_register_interface(connection, element->path,
1381                                         CONNMAN_ELEMENT_INTERFACE,
1382                                         element_methods, element_signals,
1383                                         NULL, element, NULL) == FALSE)
1384                 connman_error("Failed to register %s element", element->path);
1385
1386         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1387                 if (g_dbus_register_interface(connection, element->path,
1388                                         CONNMAN_DEVICE_INTERFACE,
1389                                         device_methods, element_signals,
1390                                         NULL, element, NULL) == FALSE)
1391                         connman_error("Failed to register %s device",
1392                                                                 element->path);
1393         }
1394
1395         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1396                 if (g_dbus_register_interface(connection, element->path,
1397                                         CONNMAN_NETWORK_INTERFACE,
1398                                         network_methods, element_signals,
1399                                         NULL, element, NULL) == FALSE)
1400                         connman_error("Failed to register %s network",
1401                                                                 element->path);
1402         }
1403
1404         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1405                 if (g_dbus_register_interface(connection, element->path,
1406                                         CONNMAN_CONNECTION_INTERFACE,
1407                                         connection_methods, element_signals,
1408                                         NULL, element, NULL) == FALSE)
1409                         connman_error("Failed to register %s connection",
1410                                                                 element->path);
1411         }
1412
1413         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1414                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
1415                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1416                                                         DBUS_TYPE_INVALID);
1417
1418         g_static_rw_lock_writer_unlock(&element_lock);
1419
1420         __connman_element_store(element);
1421
1422         g_static_rw_lock_writer_lock(&element_lock);
1423
1424         for (list = driver_list; list; list = list->next) {
1425                 struct connman_driver *driver = list->data;
1426
1427                 if (match_driver(element, driver) == FALSE)
1428                         continue;
1429
1430                 DBG("driver %p name %s", driver, driver->name);
1431
1432                 if (driver->probe(element) == 0) {
1433                         connman_element_lock(element);
1434                         element->driver = driver;
1435                         connman_element_unlock(element);
1436                         break;
1437                 }
1438         }
1439
1440         g_static_rw_lock_writer_unlock(&element_lock);
1441 }
1442
1443 static gboolean remove_element(GNode *node, gpointer user_data)
1444 {
1445         struct connman_element *element = node->data;
1446         struct connman_element *root = user_data;
1447
1448         DBG("element %p name %s", element, element->name);
1449
1450         if (element == root)
1451                 return FALSE;
1452
1453         if (element->driver) {
1454                 if (element->driver->remove)
1455                         element->driver->remove(element);
1456
1457                 connman_element_lock(element);
1458                 element->driver = NULL;
1459                 connman_element_unlock(element);
1460         }
1461
1462         if (node != NULL) {
1463                 g_node_unlink(node);
1464                 g_node_destroy(node);
1465         }
1466
1467         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1468                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
1469                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1470                                                         DBUS_TYPE_INVALID);
1471
1472         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION)
1473                 g_dbus_unregister_interface(connection, element->path,
1474                                                 CONNMAN_CONNECTION_INTERFACE);
1475
1476         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK)
1477                 g_dbus_unregister_interface(connection, element->path,
1478                                                 CONNMAN_NETWORK_INTERFACE);
1479
1480         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
1481                 g_dbus_unregister_interface(connection, element->path,
1482                                                 CONNMAN_DEVICE_INTERFACE);
1483
1484         g_dbus_unregister_interface(connection, element->path,
1485                                                 CONNMAN_ELEMENT_INTERFACE);
1486
1487         connman_element_unref(element);
1488
1489         return FALSE;
1490 }
1491
1492 static void unregister_element(gpointer data, gpointer user_data)
1493 {
1494         struct connman_element *element = data;
1495         GNode *node;
1496
1497         DBG("element %p name %s", element, element->name);
1498
1499         g_static_rw_lock_writer_lock(&element_lock);
1500
1501         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1502
1503         if (node != NULL)
1504                 g_node_traverse(node, G_POST_ORDER,
1505                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1506
1507         g_static_rw_lock_writer_unlock(&element_lock);
1508 }
1509
1510 static void unregister_children(gpointer data, gpointer user_data)
1511 {
1512         struct connman_element *element = data;
1513         GNode *node;
1514
1515         DBG("element %p name %s", element, element->name);
1516
1517         g_static_rw_lock_writer_lock(&element_lock);
1518
1519         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1520
1521         if (node != NULL)
1522                 g_node_traverse(node, G_POST_ORDER,
1523                                 G_TRAVERSE_ALL, -1, remove_element, element);
1524
1525         g_static_rw_lock_writer_unlock(&element_lock);
1526 }
1527
1528 int __connman_element_init(DBusConnection *conn, const char *device)
1529 {
1530         struct connman_element *element;
1531
1532         DBG("conn %p", conn);
1533
1534         connection = dbus_connection_ref(conn);
1535         if (connection == NULL)
1536                 return -EIO;
1537
1538         device_filter = g_strdup(device);
1539
1540         g_static_rw_lock_writer_lock(&element_lock);
1541
1542         element = connman_element_create("root");
1543
1544         element->path = g_strdup("/");
1545         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1546
1547         create_default_properties(element);
1548
1549         element_root = g_node_new(element);
1550
1551         g_static_rw_lock_writer_unlock(&element_lock);
1552
1553         thread_register = g_thread_pool_new(register_element,
1554                                                         NULL, 1, FALSE, NULL);
1555         thread_unregister = g_thread_pool_new(unregister_element,
1556                                                         NULL, 1, FALSE, NULL);
1557         thread_unregister_children = g_thread_pool_new(unregister_children,
1558                                                         NULL, 1, FALSE, NULL);
1559
1560         __connman_device_init();
1561
1562         return 0;
1563 }
1564
1565 static gboolean free_driver(GNode *node, gpointer data)
1566 {
1567         struct connman_element *element = node->data;
1568
1569         DBG("element %p name %s", element, element->name);
1570
1571         if (element->driver) {
1572                 if (element->driver->remove)
1573                         element->driver->remove(element);
1574
1575                 connman_element_lock(element);
1576                 element->driver = NULL;
1577                 connman_element_unlock(element);
1578         }
1579
1580         return FALSE;
1581 }
1582
1583 static gboolean free_node(GNode *node, gpointer data)
1584 {
1585         struct connman_element *element = node->data;
1586
1587         DBG("element %p name %s", element, element->name);
1588
1589         if (g_node_depth(node) > 1)
1590                 g_thread_pool_push(thread_unregister, element, NULL);
1591
1592         return FALSE;
1593 }
1594
1595 void __connman_element_cleanup(void)
1596 {
1597         DBG("");
1598
1599         __connman_device_cleanup();
1600
1601         g_thread_pool_free(thread_register, TRUE, TRUE);
1602         thread_register = NULL;
1603
1604         g_static_rw_lock_writer_lock(&element_lock);
1605         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1606                                                         free_driver, NULL);
1607         g_static_rw_lock_writer_unlock(&element_lock);
1608
1609         g_static_rw_lock_writer_lock(&element_lock);
1610         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1611                                                         free_node, NULL);
1612         g_static_rw_lock_writer_unlock(&element_lock);
1613
1614         g_thread_pool_free(thread_unregister, FALSE, TRUE);
1615         thread_unregister = NULL;
1616
1617         g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
1618         thread_unregister_children = NULL;
1619
1620         g_static_rw_lock_writer_lock(&element_lock);
1621         g_node_destroy(element_root);
1622         element_root = NULL;
1623         g_static_rw_lock_writer_unlock(&element_lock);
1624
1625         g_free(device_filter);
1626
1627         dbus_connection_unref(connection);
1628 }