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