Fix value of global state property
[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 user_data)
546 {
547         struct connman_element *element = node->data;
548         struct append_filter *filter = user_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 struct count_data {
579         enum connman_element_type type;
580         int count;
581 };
582
583 static gboolean count_element(GNode *node, gpointer user_data)
584 {
585         struct connman_element *element = node->data;
586         struct count_data *data = user_data;
587
588         DBG("element %p name %s", element, element->name);
589
590         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
591                 return FALSE;
592
593         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
594                                         data->type != element->type)
595                 return FALSE;
596
597         data->count++;
598
599         return FALSE;
600 }
601
602 int __connman_element_count(enum connman_element_type type)
603 {
604         struct count_data data = { type, 0 };
605
606         DBG("");
607
608         g_static_rw_lock_reader_lock(&element_lock);
609         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
610                                                         count_element, &data);
611         g_static_rw_lock_reader_unlock(&element_lock);
612
613         return data.count;
614 }
615
616 static gint compare_priority(gconstpointer a, gconstpointer b)
617 {
618         const struct connman_driver *driver1 = a;
619         const struct connman_driver *driver2 = b;
620
621         return driver2->priority - driver1->priority;
622 }
623
624 static gboolean match_driver(struct connman_element *element,
625                                         struct connman_driver *driver)
626 {
627         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
628                 return FALSE;
629
630         if (element->type != driver->type &&
631                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
632                 return FALSE;
633
634         if (element->subtype == driver->subtype ||
635                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
636                 return TRUE;
637
638         return FALSE;
639 }
640
641 static gboolean probe_driver(GNode *node, gpointer data)
642 {
643         struct connman_element *element = node->data;
644         struct connman_driver *driver = data;
645
646         DBG("element %p name %s", element, element->name);
647
648         if (!element->driver && match_driver(element, driver) == TRUE) {
649                 if (driver->probe(element) < 0)
650                         return FALSE;
651
652                 connman_element_lock(element);
653                 element->driver = driver;
654                 connman_element_unlock(element);
655         }
656
657         return FALSE;
658 }
659
660 void __connman_driver_rescan(struct connman_driver *driver)
661 {
662         DBG("driver %p name %s", driver, driver->name);
663
664         if (!driver->probe)
665                 return;
666
667         g_static_rw_lock_writer_lock(&element_lock);
668
669         if (element_root != NULL)
670                 g_node_traverse(element_root, G_PRE_ORDER,
671                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
672
673         g_static_rw_lock_writer_unlock(&element_lock);
674 }
675
676 /**
677  * connman_driver_register:
678  * @driver: driver definition
679  *
680  * Register a new driver
681  *
682  * Returns: %0 on success
683  */
684 int connman_driver_register(struct connman_driver *driver)
685 {
686         DBG("driver %p name %s", driver, driver->name);
687
688         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
689                 return -EINVAL;
690
691         if (!driver->probe)
692                 return -EINVAL;
693
694         g_static_rw_lock_writer_lock(&element_lock);
695
696         driver_list = g_slist_insert_sorted(driver_list, driver,
697                                                         compare_priority);
698
699         if (element_root != NULL)
700                 g_node_traverse(element_root, G_PRE_ORDER,
701                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
702
703         g_static_rw_lock_writer_unlock(&element_lock);
704
705         return 0;
706 }
707
708 static gboolean remove_driver(GNode *node, gpointer data)
709 {
710         struct connman_element *element = node->data;
711         struct connman_driver *driver = data;
712
713         DBG("element %p name %s", element, element->name);
714
715         if (element->driver == driver) {
716                 if (driver->remove)
717                         driver->remove(element);
718
719                 connman_element_lock(element);
720                 element->driver = NULL;
721                 connman_element_unlock(element);
722         }
723
724         return FALSE;
725 }
726
727 /**
728  * connman_driver_unregister:
729  * @driver: driver definition
730  *
731  * Remove a previously registered driver
732  */
733 void connman_driver_unregister(struct connman_driver *driver)
734 {
735         DBG("driver %p name %s", driver, driver->name);
736
737         g_static_rw_lock_writer_lock(&element_lock);
738
739         driver_list = g_slist_remove(driver_list, driver);
740
741         if (element_root != NULL)
742                 g_node_traverse(element_root, G_POST_ORDER,
743                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
744
745         g_static_rw_lock_writer_unlock(&element_lock);
746 }
747
748 /**
749  * connman_element_create:
750  * @name: element name
751  *
752  * Allocate a new element and assign the given #name to it. If the name
753  * is #NULL, it will be later on created based on the element type.
754  *
755  * Returns: a newly-allocated #connman_element structure
756  */
757 struct connman_element *connman_element_create(const char *name)
758 {
759         struct connman_element *element;
760
761         element = g_try_new0(struct connman_element, 1);
762         if (element == NULL)
763                 return NULL;
764
765         DBG("element %p", element);
766
767         element->refcount = 1;
768
769         g_static_mutex_init(&element->mutex);
770
771         element->name    = g_strdup(name);
772         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
773         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
774         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
775         element->index   = -1;
776         element->enabled = FALSE;
777
778         return element;
779 }
780
781 struct connman_element *connman_element_ref(struct connman_element *element)
782 {
783         DBG("element %p name %s refcount %d", element, element->name,
784                                 g_atomic_int_get(&element->refcount) + 1);
785
786         g_atomic_int_inc(&element->refcount);
787
788         return element;
789 }
790
791 static void free_properties(struct connman_element *element)
792 {
793         GSList *list;
794
795         DBG("element %p name %s", element, element->name);
796
797         connman_element_lock(element);
798
799         for (list = element->properties; list; list = list->next) {
800                 struct connman_property *property = list->data;
801
802                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) {
803                         if (property->type == DBUS_TYPE_STRING)
804                                 g_free(property->value);
805                         if (property->type == DBUS_TYPE_ARRAY &&
806                                         property->subtype == DBUS_TYPE_BYTE)
807                                 g_free(property->value);
808                 }
809
810                 g_free(property);
811         }
812
813         g_slist_free(element->properties);
814
815         element->properties = NULL;
816
817         connman_element_unlock(element);
818 }
819
820 void connman_element_unref(struct connman_element *element)
821 {
822         DBG("element %p name %s refcount %d", element, element->name,
823                                 g_atomic_int_get(&element->refcount) - 1);
824
825         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
826                 free_properties(element);
827                 g_free(element->ipv4.address);
828                 g_free(element->ipv4.netmask);
829                 g_free(element->ipv4.gateway);
830                 g_free(element->ipv4.network);
831                 g_free(element->ipv4.broadcast);
832                 g_free(element->ipv4.nameserver);
833                 g_free(element->path);
834                 g_free(element->name);
835                 g_free(element);
836         }
837 }
838
839 int connman_element_add_static_property(struct connman_element *element,
840                                 const char *name, int type, const void *value)
841 {
842         struct connman_property *property;
843
844         DBG("element %p name %s", element, element->name);
845
846         if (type != DBUS_TYPE_STRING)
847                 return -EINVAL;
848
849         property = g_try_new0(struct connman_property, 1);
850         if (property == NULL)
851                 return -ENOMEM;
852
853         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
854         property->id    = CONNMAN_PROPERTY_ID_INVALID;
855         property->name  = g_strdup(name);
856         property->type  = type;
857
858         DBG("name %s type %d value %p", name, type, value);
859
860         switch (type) {
861         case DBUS_TYPE_STRING:
862                 property->value = g_strdup(*((const char **) value));
863                 break;
864         }
865
866         connman_element_lock(element);
867         element->properties = g_slist_append(element->properties, property);
868         connman_element_unlock(element);
869
870         return 0;
871 }
872
873 int connman_element_add_static_array_property(struct connman_element *element,
874                         const char *name, int type, const void *value, int len)
875 {
876         struct connman_property *property;
877
878         DBG("element %p name %s", element, element->name);
879
880         if (type != DBUS_TYPE_BYTE)
881                 return -EINVAL;
882
883         property = g_try_new0(struct connman_property, 1);
884         if (property == NULL)
885                 return -ENOMEM;
886
887         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
888         property->id      = CONNMAN_PROPERTY_ID_INVALID;
889         property->name    = g_strdup(name);
890         property->type    = DBUS_TYPE_ARRAY;
891         property->subtype = type;
892
893         DBG("name %s type %d value %p", name, type, value);
894
895         switch (type) {
896         case DBUS_TYPE_BYTE:
897                 property->value = g_try_malloc(len);
898                 if (property->value != NULL) {
899                         memcpy(property->value,
900                                 *((const unsigned char **) value), len);
901                         property->size = len;
902                 }
903                 break;
904         }
905
906         connman_element_lock(element);
907         element->properties = g_slist_append(element->properties, property);
908         connman_element_unlock(element);
909
910         return 0;
911 }
912
913 static void *get_reference_value(struct connman_element *element,
914                                                 enum connman_property_id id)
915 {
916         GSList *list;
917
918         DBG("element %p name %s", element, element->name);
919
920         for (list = element->properties; list; list = list->next) {
921                 struct connman_property *property = list->data;
922
923                 if (property->id != id)
924                         continue;
925
926                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
927                         return property->value;
928         }
929
930         if (element->parent == NULL)
931                 return NULL;
932
933         return get_reference_value(element->parent, id);
934 }
935
936 static void set_reference_properties(struct connman_element *element)
937 {
938         GSList *list;
939
940         DBG("element %p name %s", element, element->name);
941
942         for (list = element->properties; list; list = list->next) {
943                 struct connman_property *property = list->data;
944
945                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
946                         continue;
947
948                 property->value = get_reference_value(element->parent,
949                                                                 property->id);
950         }
951 }
952
953 static struct connman_property *create_property(struct connman_element *element,
954                                                 enum connman_property_id id)
955 {
956         struct connman_property *property;
957         GSList *list;
958
959         DBG("element %p name %s", element, element->name);
960
961         connman_element_lock(element);
962
963         for (list = element->properties; list; list = list->next) {
964                 property = list->data;
965
966                 if (property->id == id)
967                         goto unlock;
968         }
969
970         property = g_try_new0(struct connman_property, 1);
971         if (property == NULL)
972                 goto unlock;
973
974         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
975         property->id    = id;
976         property->name  = g_strdup(propid2name(id));
977         property->type  = propid2type(id);
978
979         if (property->name == NULL) {
980                 g_free(property);
981                 property = NULL;
982                 goto unlock;
983         }
984
985         element->properties = g_slist_append(element->properties, property);
986
987 unlock:
988         connman_element_unlock(element);
989
990         return property;
991 }
992
993 static void create_default_properties(struct connman_element *element)
994 {
995         struct connman_property *property;
996         int i;
997
998         DBG("element %p name %s", element, element->name);
999
1000         for (i = 0; propid_table[i].name; i++) {
1001                 DBG("property %s", propid_table[i].name);
1002
1003                 property = create_property(element, propid_table[i].id);
1004
1005                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1006
1007                 if (propid_table[i].type != DBUS_TYPE_STRING)
1008                         continue;
1009
1010                 if (propid_table[i].value)
1011                         property->value = g_strdup(propid_table[i].value);
1012                 else
1013                         property->value = g_strdup("");
1014         }
1015 }
1016
1017 static int define_properties_valist(struct connman_element *element,
1018                                                                 va_list args)
1019 {
1020         enum connman_property_id id;
1021
1022         DBG("element %p name %s", element, element->name);
1023
1024         id = va_arg(args, enum connman_property_id);
1025
1026         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1027
1028                 DBG("property %d", id);
1029
1030                 create_property(element, id);
1031
1032                 id = va_arg(args, enum connman_property_id);
1033         }
1034
1035         return 0;
1036 }
1037
1038 /**
1039  * connman_element_define_properties:
1040  * @element: an element
1041  * @varargs: list of property identifiers
1042  *
1043  * Define the valid properties for an element.
1044  *
1045  * Returns: %0 on success
1046  */
1047 int connman_element_define_properties(struct connman_element *element, ...)
1048 {
1049         va_list args;
1050         int err;
1051
1052         DBG("element %p name %s", element, element->name);
1053
1054         va_start(args, element);
1055
1056         err = define_properties_valist(element, args);
1057
1058         va_end(args);
1059
1060         return err;
1061 }
1062
1063 int connman_element_create_property(struct connman_element *element,
1064                                                 const char *name, int type)
1065 {
1066         return -EIO;
1067 }
1068
1069 int connman_element_set_property(struct connman_element *element,
1070                                 enum connman_property_id id, const void *value)
1071 {
1072         switch (id) {
1073         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1074                 connman_element_lock(element);
1075                 g_free(element->ipv4.address);
1076                 element->ipv4.address = g_strdup(*((const char **) value));
1077                 connman_element_unlock(element);
1078                 break;
1079         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1080                 connman_element_lock(element);
1081                 g_free(element->ipv4.netmask);
1082                 element->ipv4.netmask = g_strdup(*((const char **) value));
1083                 connman_element_unlock(element);
1084                 break;
1085         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1086                 connman_element_lock(element);
1087                 g_free(element->ipv4.gateway);
1088                 element->ipv4.gateway = g_strdup(*((const char **) value));
1089                 connman_element_unlock(element);
1090                 break;
1091         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1092                 connman_element_lock(element);
1093                 g_free(element->ipv4.nameserver);
1094                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1095                 connman_element_unlock(element);
1096                 break;
1097         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1098                 connman_element_lock(element);
1099                 g_free(element->wifi.security);
1100                 element->wifi.security = g_strdup(*((const char **) value));
1101                 connman_element_unlock(element);
1102                 break;
1103         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1104                 connman_element_lock(element);
1105                 g_free(element->wifi.passphrase);
1106                 element->wifi.passphrase = g_strdup(*((const char **) value));
1107                 connman_element_unlock(element);
1108                 break;
1109         default:
1110                 return -EINVAL;
1111         }
1112
1113         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1114                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1115                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1116                                                         DBUS_TYPE_INVALID);
1117
1118         return 0;
1119 }
1120
1121 int connman_element_get_value(struct connman_element *element,
1122                                 enum connman_property_id id, void *value)
1123 {
1124         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1125                 return -EINVAL;
1126
1127         switch (id) {
1128         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1129                 if (element->ipv4.address == NULL)
1130                         return connman_element_get_value(element->parent,
1131                                                                 id, value);
1132                 connman_element_lock(element);
1133                 *((char **) value) = element->ipv4.address;
1134                 connman_element_unlock(element);
1135                 break;
1136         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1137                 if (element->ipv4.netmask == NULL)
1138                         return connman_element_get_value(element->parent,
1139                                                                 id, value);
1140                 connman_element_lock(element);
1141                 *((char **) value) = element->ipv4.netmask;
1142                 connman_element_unlock(element);
1143                 break;
1144         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1145                 if (element->ipv4.gateway == NULL)
1146                         return connman_element_get_value(element->parent,
1147                                                                 id, value);
1148                 connman_element_lock(element);
1149                 *((char **) value) = element->ipv4.gateway;
1150                 connman_element_unlock(element);
1151                 break;
1152         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1153                 if (element->ipv4.nameserver == NULL)
1154                         return connman_element_get_value(element->parent,
1155                                                                 id, value);
1156                 connman_element_lock(element);
1157                 *((char **) value) = element->ipv4.nameserver;
1158                 connman_element_unlock(element);
1159                 break;
1160         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1161                 if (element->wifi.security == NULL)
1162                         return connman_element_get_value(element->parent,
1163                                                                 id, value);
1164                 connman_element_lock(element);
1165                 *((char **) value) = element->wifi.security;
1166                 connman_element_unlock(element);
1167                 break;
1168         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1169                 if (element->wifi.passphrase == NULL)
1170                         return connman_element_get_value(element->parent,
1171                                                                 id, value);
1172                 connman_element_lock(element);
1173                 *((char **) value) = element->wifi.passphrase;
1174                 connman_element_unlock(element);
1175                 break;
1176         default:
1177                 return -EINVAL;
1178         }
1179
1180         return 0;
1181 }
1182
1183 gboolean connman_element_get_static_property(struct connman_element *element,
1184                                                 const char *name, void *value)
1185 {
1186         GSList *list;
1187         gboolean found = FALSE;
1188
1189         DBG("element %p name %s", element, element->name);
1190
1191         connman_element_lock(element);
1192
1193         for (list = element->properties; list; list = list->next) {
1194                 struct connman_property *property = list->data;
1195
1196                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1197                         continue;
1198
1199                 if (g_str_equal(property->name, name) == TRUE) {
1200                         *((char **) value) = property->value;
1201                         found = TRUE;
1202                         break;
1203                 }
1204         }
1205
1206         connman_element_unlock(element);
1207
1208         return found;
1209 }
1210
1211 gboolean connman_element_get_static_array_property(struct connman_element *element,
1212                                         const char *name, void *value, int *len)
1213 {
1214         GSList *list;
1215         gboolean found = FALSE;
1216
1217         DBG("element %p name %s", element, element->name);
1218
1219         connman_element_lock(element);
1220
1221         for (list = element->properties; list; list = list->next) {
1222                 struct connman_property *property = list->data;
1223
1224                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1225                         continue;
1226
1227                 if (g_str_equal(property->name, name) == TRUE) {
1228                         *((char **) value) = property->value;
1229                         *len = property->size;
1230                         found = TRUE;
1231                         break;
1232                 }
1233         }
1234
1235         connman_element_unlock(element);
1236
1237         return found;
1238 }
1239
1240 gboolean connman_element_match_static_property(struct connman_element *element,
1241                                         const char *name, const void *value)
1242 {
1243         GSList *list;
1244         gboolean result = FALSE;
1245
1246         DBG("element %p name %s", element, element->name);
1247
1248         connman_element_lock(element);
1249
1250         for (list = element->properties; list; list = list->next) {
1251                 struct connman_property *property = list->data;
1252
1253                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1254                         continue;
1255
1256                 if (g_str_equal(property->name, name) == FALSE)
1257                         continue;
1258
1259                 if (property->type == DBUS_TYPE_STRING)
1260                         result = g_str_equal(property->value,
1261                                                 *((const char **) value));
1262
1263                 if (result == TRUE)
1264                         break;
1265         }
1266
1267         connman_element_unlock(element);
1268
1269         return result;
1270 }
1271
1272 /**
1273  * connman_element_register:
1274  * @element: the element to register
1275  * @parent: the parent to register the element with
1276  *
1277  * Register an element with the core. It will be register under the given
1278  * parent of if %NULL is provided under the root element.
1279  *
1280  * Returns: %0 on success
1281  */
1282 int connman_element_register(struct connman_element *element,
1283                                         struct connman_element *parent)
1284 {
1285         DBG("element %p name %s parent %p", element, element->name, parent);
1286
1287         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1288                 if (g_pattern_match_simple(device_filter,
1289                                                 element->name) == FALSE) {
1290                         DBG("ignoring %s device", element->name);
1291                         return -EPERM;
1292                 }
1293         }
1294
1295         if (connman_element_ref(element) == NULL)
1296                 return -EINVAL;
1297
1298         connman_element_lock(element);
1299
1300         if (element->name == NULL) {
1301                 element->name = g_strdup(type2string(element->type));
1302                 if (element->name == NULL) {
1303                         connman_element_unlock(element);
1304                         return -EINVAL;
1305                 }
1306         }
1307
1308         element->parent = parent;
1309
1310         connman_element_unlock(element);
1311
1312         if (thread_register != NULL)
1313                 g_thread_pool_push(thread_register, element, NULL);
1314
1315         return 0;
1316 }
1317
1318 void connman_element_unregister(struct connman_element *element)
1319 {
1320         DBG("element %p name %s", element, element->name);
1321
1322         if (thread_unregister != NULL)
1323                 g_thread_pool_push(thread_unregister, element, NULL);
1324 }
1325
1326 void connman_element_unregister_children(struct connman_element *element)
1327 {
1328         DBG("element %p name %s", element, element->name);
1329
1330         if (thread_unregister_children != NULL)
1331                 g_thread_pool_push(thread_unregister_children, element, NULL);
1332 }
1333
1334 static gboolean update_element(GNode *node, gpointer user_data)
1335 {
1336         struct connman_element *element = node->data;
1337
1338         DBG("element %p name %s", element, element->name);
1339
1340         if (element->driver && element->driver->update)
1341                 element->driver->update(element);
1342
1343         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1344                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1345                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1346                                                         DBUS_TYPE_INVALID);
1347
1348         return FALSE;
1349 }
1350
1351 void connman_element_update(struct connman_element *element)
1352 {
1353         GNode *node;
1354
1355         DBG("element %p name %s", element, element->name);
1356
1357         g_static_rw_lock_reader_lock(&element_lock);
1358
1359         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1360
1361         if (node != NULL)
1362                 g_node_traverse(node, G_PRE_ORDER,
1363                                 G_TRAVERSE_ALL, -1, update_element, NULL);
1364
1365         g_static_rw_lock_reader_unlock(&element_lock);
1366 }
1367
1368 int connman_element_set_enabled(struct connman_element *element,
1369                                                         gboolean enabled)
1370 {
1371         if (element->enabled == enabled)
1372                 return 0;
1373
1374         element->enabled = enabled;
1375
1376         connman_element_update(element);
1377
1378         return 0;
1379 }
1380
1381 static void register_element(gpointer data, gpointer user_data)
1382 {
1383         struct connman_element *element = data;
1384         const gchar *basepath;
1385         GSList *list;
1386         GNode *node;
1387
1388         g_static_rw_lock_writer_lock(&element_lock);
1389
1390         connman_element_lock(element);
1391
1392         if (element->parent) {
1393                 node = g_node_find(element_root, G_PRE_ORDER,
1394                                         G_TRAVERSE_ALL, element->parent);
1395                 basepath = element->parent->path;
1396
1397                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1398                         element->subtype = element->parent->subtype;
1399         } else {
1400                 element->parent = element_root->data;
1401
1402                 node = element_root;
1403                 basepath = "";
1404         }
1405
1406         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1407
1408         set_reference_properties(element);
1409
1410         connman_element_unlock(element);
1411
1412         DBG("element %p path %s", element, element->path);
1413
1414         __connman_element_load(element);
1415
1416         g_node_append_data(node, element);
1417
1418         if (g_dbus_register_interface(connection, element->path,
1419                                         CONNMAN_ELEMENT_INTERFACE,
1420                                         element_methods, element_signals,
1421                                         NULL, element, NULL) == FALSE)
1422                 connman_error("Failed to register %s element", element->path);
1423
1424         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1425                 if (g_dbus_register_interface(connection, element->path,
1426                                         CONNMAN_DEVICE_INTERFACE,
1427                                         device_methods, element_signals,
1428                                         NULL, element, NULL) == FALSE)
1429                         connman_error("Failed to register %s device",
1430                                                                 element->path);
1431         }
1432
1433         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1434                 if (g_dbus_register_interface(connection, element->path,
1435                                         CONNMAN_NETWORK_INTERFACE,
1436                                         network_methods, element_signals,
1437                                         NULL, element, NULL) == FALSE)
1438                         connman_error("Failed to register %s network",
1439                                                                 element->path);
1440         }
1441
1442         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1443                 if (g_dbus_register_interface(connection, element->path,
1444                                         CONNMAN_CONNECTION_INTERFACE,
1445                                         connection_methods, element_signals,
1446                                         NULL, element, NULL) == FALSE)
1447                         connman_error("Failed to register %s connection",
1448                                                                 element->path);
1449         }
1450
1451         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1452                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
1453                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1454                                                         DBUS_TYPE_INVALID);
1455
1456         g_static_rw_lock_writer_unlock(&element_lock);
1457
1458         __connman_element_store(element);
1459
1460         g_static_rw_lock_writer_lock(&element_lock);
1461
1462         for (list = driver_list; list; list = list->next) {
1463                 struct connman_driver *driver = list->data;
1464
1465                 if (match_driver(element, driver) == FALSE)
1466                         continue;
1467
1468                 DBG("driver %p name %s", driver, driver->name);
1469
1470                 if (driver->probe(element) == 0) {
1471                         connman_element_lock(element);
1472                         element->driver = driver;
1473                         connman_element_unlock(element);
1474                         break;
1475                 }
1476         }
1477
1478         g_static_rw_lock_writer_unlock(&element_lock);
1479 }
1480
1481 static gboolean remove_element(GNode *node, gpointer user_data)
1482 {
1483         struct connman_element *element = node->data;
1484         struct connman_element *root = user_data;
1485
1486         DBG("element %p name %s", element, element->name);
1487
1488         if (element == root)
1489                 return FALSE;
1490
1491         if (element->driver) {
1492                 if (element->driver->remove)
1493                         element->driver->remove(element);
1494
1495                 connman_element_lock(element);
1496                 element->driver = NULL;
1497                 connman_element_unlock(element);
1498         }
1499
1500         if (node != NULL) {
1501                 g_node_unlink(node);
1502                 g_node_destroy(node);
1503         }
1504
1505         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1506                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
1507                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1508                                                         DBUS_TYPE_INVALID);
1509
1510         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION)
1511                 g_dbus_unregister_interface(connection, element->path,
1512                                                 CONNMAN_CONNECTION_INTERFACE);
1513
1514         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK)
1515                 g_dbus_unregister_interface(connection, element->path,
1516                                                 CONNMAN_NETWORK_INTERFACE);
1517
1518         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
1519                 g_dbus_unregister_interface(connection, element->path,
1520                                                 CONNMAN_DEVICE_INTERFACE);
1521
1522         g_dbus_unregister_interface(connection, element->path,
1523                                                 CONNMAN_ELEMENT_INTERFACE);
1524
1525         connman_element_unref(element);
1526
1527         return FALSE;
1528 }
1529
1530 static void unregister_element(gpointer data, gpointer user_data)
1531 {
1532         struct connman_element *element = data;
1533         GNode *node;
1534
1535         DBG("element %p name %s", element, element->name);
1536
1537         g_static_rw_lock_writer_lock(&element_lock);
1538
1539         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1540
1541         if (node != NULL)
1542                 g_node_traverse(node, G_POST_ORDER,
1543                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1544
1545         g_static_rw_lock_writer_unlock(&element_lock);
1546 }
1547
1548 static void unregister_children(gpointer data, gpointer user_data)
1549 {
1550         struct connman_element *element = data;
1551         GNode *node;
1552
1553         DBG("element %p name %s", element, element->name);
1554
1555         g_static_rw_lock_writer_lock(&element_lock);
1556
1557         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1558
1559         if (node != NULL)
1560                 g_node_traverse(node, G_POST_ORDER,
1561                                 G_TRAVERSE_ALL, -1, remove_element, element);
1562
1563         g_static_rw_lock_writer_unlock(&element_lock);
1564 }
1565
1566 int __connman_element_init(DBusConnection *conn, const char *device)
1567 {
1568         struct connman_element *element;
1569
1570         DBG("conn %p", conn);
1571
1572         connection = dbus_connection_ref(conn);
1573         if (connection == NULL)
1574                 return -EIO;
1575
1576         device_filter = g_strdup(device);
1577
1578         g_static_rw_lock_writer_lock(&element_lock);
1579
1580         element = connman_element_create("root");
1581
1582         element->path = g_strdup("/");
1583         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1584
1585         create_default_properties(element);
1586
1587         element_root = g_node_new(element);
1588
1589         g_static_rw_lock_writer_unlock(&element_lock);
1590
1591         thread_register = g_thread_pool_new(register_element,
1592                                                         NULL, 1, FALSE, NULL);
1593         thread_unregister = g_thread_pool_new(unregister_element,
1594                                                         NULL, 1, FALSE, NULL);
1595         thread_unregister_children = g_thread_pool_new(unregister_children,
1596                                                         NULL, 1, FALSE, NULL);
1597
1598         __connman_device_init();
1599
1600         return 0;
1601 }
1602
1603 static gboolean free_driver(GNode *node, gpointer data)
1604 {
1605         struct connman_element *element = node->data;
1606
1607         DBG("element %p name %s", element, element->name);
1608
1609         if (element->driver) {
1610                 if (element->driver->remove)
1611                         element->driver->remove(element);
1612
1613                 connman_element_lock(element);
1614                 element->driver = NULL;
1615                 connman_element_unlock(element);
1616         }
1617
1618         return FALSE;
1619 }
1620
1621 static gboolean free_node(GNode *node, gpointer data)
1622 {
1623         struct connman_element *element = node->data;
1624
1625         DBG("element %p name %s", element, element->name);
1626
1627         if (g_node_depth(node) > 1)
1628                 g_thread_pool_push(thread_unregister, element, NULL);
1629
1630         return FALSE;
1631 }
1632
1633 void __connman_element_cleanup(void)
1634 {
1635         DBG("");
1636
1637         __connman_device_cleanup();
1638
1639         g_thread_pool_free(thread_register, TRUE, TRUE);
1640         thread_register = NULL;
1641
1642         g_static_rw_lock_writer_lock(&element_lock);
1643         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1644                                                         free_driver, NULL);
1645         g_static_rw_lock_writer_unlock(&element_lock);
1646
1647         g_static_rw_lock_writer_lock(&element_lock);
1648         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1649                                                         free_node, NULL);
1650         g_static_rw_lock_writer_unlock(&element_lock);
1651
1652         g_thread_pool_free(thread_unregister, FALSE, TRUE);
1653         thread_unregister = NULL;
1654
1655         g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
1656         thread_unregister_children = NULL;
1657
1658         g_static_rw_lock_writer_lock(&element_lock);
1659         g_node_destroy(element_root);
1660         element_root = NULL;
1661         g_static_rw_lock_writer_unlock(&element_lock);
1662
1663         g_free(device_filter);
1664
1665         dbus_connection_unref(connection);
1666 }