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