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