element: Remove IPv6
[framework/connectivity/connman.git] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 static gchar **nodevice_filter = NULL;
41
42 static gboolean started = FALSE;
43
44 static const char *type2string(enum connman_element_type type)
45 {
46         switch (type) {
47         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
48                 return "unknown";
49         case CONNMAN_ELEMENT_TYPE_ROOT:
50                 return "root";
51         case CONNMAN_ELEMENT_TYPE_DEVICE:
52                 return "device";
53         case CONNMAN_ELEMENT_TYPE_NETWORK:
54                 return "network";
55         }
56
57         return NULL;
58 }
59
60 struct foreach_data {
61         enum connman_element_type type;
62         element_cb_t callback;
63         gpointer user_data;
64 };
65
66 static gboolean foreach_callback(GNode *node, gpointer user_data)
67 {
68         struct connman_element *element = node->data;
69         struct foreach_data *data = user_data;
70
71         DBG("element %p name %s", element, element->name);
72
73         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
74                 return FALSE;
75
76         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
77                                         data->type != element->type)
78                 return FALSE;
79
80         if (data->callback)
81                 data->callback(element, data->user_data);
82
83         return FALSE;
84 }
85
86 void __connman_element_foreach(struct connman_element *element,
87                                 enum connman_element_type type,
88                                 element_cb_t callback, gpointer user_data)
89 {
90         struct foreach_data data = { type, callback, user_data };
91         GNode *node;
92
93         DBG("");
94
95         if (element != NULL) {
96                 node = g_node_find(element_root, G_PRE_ORDER,
97                                                 G_TRAVERSE_ALL, element);
98                 if (node == NULL)
99                         return;
100         } else
101                 node = element_root;
102
103         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
104                                                 foreach_callback, &data);
105 }
106
107 struct append_filter {
108         enum connman_element_type type;
109         DBusMessageIter *iter;
110 };
111
112 static gboolean append_path(GNode *node, gpointer user_data)
113 {
114         struct connman_element *element = node->data;
115         struct append_filter *filter = user_data;
116
117         DBG("element %p name %s", element, element->name);
118
119         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
120                 return FALSE;
121
122         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
123                                         filter->type != element->type)
124                 return FALSE;
125
126         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
127                         __connman_device_has_driver(element->device) == FALSE)
128                 return FALSE;
129
130         if (filter->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
131                         __connman_network_has_driver(element->network) == FALSE)
132                 return FALSE;
133
134         dbus_message_iter_append_basic(filter->iter,
135                                 DBUS_TYPE_OBJECT_PATH, &element->path);
136
137         return FALSE;
138 }
139
140 void __connman_element_list(struct connman_element *element,
141                                         enum connman_element_type type,
142                                                         DBusMessageIter *iter)
143 {
144         struct append_filter filter = { type, iter };
145         GNode *node;
146
147         DBG("");
148
149         if (element != NULL) {
150                 node = g_node_find(element_root, G_PRE_ORDER,
151                                                 G_TRAVERSE_ALL, element);
152                 if (node == NULL)
153                         return;
154         } else
155                 node = element_root;
156
157         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
158                                                 append_path, &filter);
159 }
160
161 static struct connman_network *get_network(struct connman_element *element)
162 {
163         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
164                                                 element->network != NULL)
165                 return element->network;
166
167         if (element->parent == NULL)
168                 return NULL;
169
170         return get_network(element->parent);
171 }
172
173 struct connman_service *__connman_element_get_service(struct connman_element *element)
174 {
175         struct connman_service *service = NULL;
176         struct connman_network *network;
177         struct connman_device *device;
178         enum connman_device_type type;
179
180         device = __connman_element_get_device(element);
181         if (device == NULL) {
182                 /* Workaround for the connection removal. */
183                 service = __connman_service_lookup_from_index(element->index);
184                 return service;
185         }
186
187         type = connman_device_get_type(device);
188
189         switch (type) {
190         case CONNMAN_DEVICE_TYPE_UNKNOWN:
191         case CONNMAN_DEVICE_TYPE_VENDOR:
192         case CONNMAN_DEVICE_TYPE_GPS:
193         case CONNMAN_DEVICE_TYPE_GADGET:
194                 break;
195         case CONNMAN_DEVICE_TYPE_ETHERNET:
196         case CONNMAN_DEVICE_TYPE_WIFI:
197         case CONNMAN_DEVICE_TYPE_WIMAX:
198         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
199         case CONNMAN_DEVICE_TYPE_CELLULAR:
200                 network = get_network(element);
201                 if (network == NULL)
202                         return NULL;
203                 service = __connman_service_lookup_from_network(network);
204                 break;
205         }
206
207         return service;
208 }
209
210 struct connman_device *__connman_element_get_device(struct connman_element *element)
211 {
212         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
213                                                 element->device != NULL)
214                 return element->device;
215
216         if (element->parent == NULL)
217                 return NULL;
218
219         return __connman_element_get_device(element->parent);
220 }
221
222 struct find_data {
223         enum connman_service_type type;
224         struct connman_device *device;
225         connman_bool_t error;
226 };
227
228 static gboolean find_device(GNode *node, gpointer user_data)
229 {
230         struct connman_element *element = node->data;
231         struct find_data *data = user_data;
232
233         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
234                 return FALSE;
235
236         if (element->device == NULL)
237                 return FALSE;
238
239         if (data->type != __connman_device_get_service_type(element->device))
240                 return FALSE;
241
242         data->device = element->device;
243
244         return TRUE;
245 }
246
247 struct connman_device *__connman_element_find_device(enum connman_service_type type)
248 {
249         struct find_data data = { .type = type, .device = NULL };
250
251         g_node_traverse(element_root, G_PRE_ORDER,
252                                 G_TRAVERSE_ALL, -1, find_device, &data);
253
254         return data.device;
255 }
256
257 static gboolean request_scan(GNode *node, gpointer user_data)
258 {
259         struct connman_element *element = node->data;
260         struct find_data *data = user_data;
261         enum connman_service_type type;
262
263         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
264                 return FALSE;
265
266         if (element->device == NULL)
267                 return FALSE;
268
269         type = __connman_device_get_service_type(element->device);
270
271         switch (type) {
272         case CONNMAN_SERVICE_TYPE_UNKNOWN:
273         case CONNMAN_SERVICE_TYPE_SYSTEM:
274         case CONNMAN_SERVICE_TYPE_ETHERNET:
275         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
276         case CONNMAN_SERVICE_TYPE_CELLULAR:
277         case CONNMAN_SERVICE_TYPE_GPS:
278         case CONNMAN_SERVICE_TYPE_VPN:
279         case CONNMAN_SERVICE_TYPE_GADGET:
280                 return FALSE;
281         case CONNMAN_SERVICE_TYPE_WIFI:
282         case CONNMAN_SERVICE_TYPE_WIMAX:
283                 if (data->type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
284                                                         data->type != type)
285                         return FALSE;
286                 break;
287         }
288
289         __connman_device_scan(element->device);
290
291         return FALSE;
292 }
293
294 int __connman_element_request_scan(enum connman_service_type type)
295 {
296         struct find_data data = { .type = type, .device = NULL };
297
298         g_node_traverse(element_root, G_PRE_ORDER,
299                                 G_TRAVERSE_ALL, -1, request_scan, &data);
300
301         return 0;
302 }
303
304 static gboolean enable_technology(GNode *node, gpointer user_data)
305 {
306         struct connman_element *element = node->data;
307         struct find_data *data = user_data;
308         enum connman_service_type type;
309         int err;
310
311         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
312                 return FALSE;
313
314         if (element->device == NULL)
315                 return FALSE;
316
317         type = __connman_device_get_service_type(element->device);
318
319         switch (type) {
320         case CONNMAN_SERVICE_TYPE_UNKNOWN:
321         case CONNMAN_SERVICE_TYPE_SYSTEM:
322         case CONNMAN_SERVICE_TYPE_GPS:
323         case CONNMAN_SERVICE_TYPE_VPN:
324         case CONNMAN_SERVICE_TYPE_GADGET:
325                 return FALSE;
326         case CONNMAN_SERVICE_TYPE_ETHERNET:
327         case CONNMAN_SERVICE_TYPE_WIFI:
328         case CONNMAN_SERVICE_TYPE_WIMAX:
329         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
330         case CONNMAN_SERVICE_TYPE_CELLULAR:
331                 if (data->type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
332                                                         data->type != type)
333                         return FALSE;
334                 break;
335         }
336
337         err = __connman_device_enable_persistent(element->device);
338         if (err == 0 || (err < 0 && err == -EINPROGRESS))
339                 data->error = FALSE;
340
341         return FALSE;
342 }
343
344 int __connman_element_enable_technology(enum connman_service_type type)
345 {
346         struct find_data data = { .type = type, .device = NULL, .error = TRUE };
347
348         g_node_traverse(element_root, G_PRE_ORDER,
349                                 G_TRAVERSE_ALL, -1, enable_technology, &data);
350
351         if (data.error == TRUE)
352                 return -ENODEV;
353
354         return 0;
355 }
356
357 static gboolean disable_technology(GNode *node, gpointer user_data)
358 {
359         struct connman_element *element = node->data;
360         struct find_data *data = user_data;
361         enum connman_service_type type;
362         int err;
363
364         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
365                 return FALSE;
366
367         if (element->device == NULL)
368                 return FALSE;
369
370         type = __connman_device_get_service_type(element->device);
371
372         switch (type) {
373         case CONNMAN_SERVICE_TYPE_UNKNOWN:
374         case CONNMAN_SERVICE_TYPE_SYSTEM:
375         case CONNMAN_SERVICE_TYPE_GPS:
376         case CONNMAN_SERVICE_TYPE_VPN:
377         case CONNMAN_SERVICE_TYPE_GADGET:
378                 return FALSE;
379         case CONNMAN_SERVICE_TYPE_ETHERNET:
380         case CONNMAN_SERVICE_TYPE_WIFI:
381         case CONNMAN_SERVICE_TYPE_WIMAX:
382         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
383         case CONNMAN_SERVICE_TYPE_CELLULAR:
384                 if (data->type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
385                                                         data->type != type)
386                         return FALSE;
387                 break;
388         }
389
390         err = __connman_device_disable_persistent(element->device);
391         if (err == 0 || (err < 0 && err == -EINPROGRESS))
392                 data->error = FALSE;
393
394         return FALSE;
395 }
396
397 int __connman_element_disable_technology(enum connman_service_type type)
398 {
399         struct find_data data = { .type = type, .device = NULL, .error = TRUE };
400
401         g_node_traverse(element_root, G_PRE_ORDER,
402                                 G_TRAVERSE_ALL, -1, disable_technology, &data);
403
404         if (data.error == TRUE)
405                 return -ENODEV;
406
407         return 0;
408 }
409
410 static gint compare_priority(gconstpointer a, gconstpointer b)
411 {
412         const struct connman_driver *driver1 = a;
413         const struct connman_driver *driver2 = b;
414
415         return driver2->priority - driver1->priority;
416 }
417
418 static gboolean match_driver(struct connman_element *element,
419                                         struct connman_driver *driver)
420 {
421         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
422                 return FALSE;
423
424         if (element->type == driver->type ||
425                         driver->type == CONNMAN_ELEMENT_TYPE_UNKNOWN)
426                 return TRUE;
427
428         return FALSE;
429 }
430
431 static gboolean probe_driver(GNode *node, gpointer data)
432 {
433         struct connman_element *element = node->data;
434         struct connman_driver *driver = data;
435
436         DBG("element %p name %s", element, element->name);
437
438         if (!element->driver && match_driver(element, driver) == TRUE) {
439                 if (driver->probe(element) < 0)
440                         return FALSE;
441
442                 element->driver = driver;
443         }
444
445         return FALSE;
446 }
447
448 void __connman_driver_rescan(struct connman_driver *driver)
449 {
450         DBG("driver %p name %s", driver, driver->name);
451
452         if (!driver->probe)
453                 return;
454
455         if (element_root != NULL)
456                 g_node_traverse(element_root, G_PRE_ORDER,
457                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
458 }
459
460 /**
461  * connman_driver_register:
462  * @driver: driver definition
463  *
464  * Register a new driver
465  *
466  * Returns: %0 on success
467  */
468 int connman_driver_register(struct connman_driver *driver)
469 {
470         DBG("driver %p name %s", driver, driver->name);
471
472         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
473                 return -EINVAL;
474
475         if (!driver->probe)
476                 return -EINVAL;
477
478         driver_list = g_slist_insert_sorted(driver_list, driver,
479                                                         compare_priority);
480
481         if (started == FALSE)
482                 return 0;
483
484         if (element_root != NULL)
485                 g_node_traverse(element_root, G_PRE_ORDER,
486                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
487
488         return 0;
489 }
490
491 static gboolean remove_driver(GNode *node, gpointer data)
492 {
493         struct connman_element *element = node->data;
494         struct connman_driver *driver = data;
495
496         DBG("element %p name %s", element, element->name);
497
498         if (element->driver == driver) {
499                 if (driver->remove)
500                         driver->remove(element);
501
502                 element->driver = NULL;
503         }
504
505         return FALSE;
506 }
507
508 /**
509  * connman_driver_unregister:
510  * @driver: driver definition
511  *
512  * Remove a previously registered driver
513  */
514 void connman_driver_unregister(struct connman_driver *driver)
515 {
516         DBG("driver %p name %s", driver, driver->name);
517
518         driver_list = g_slist_remove(driver_list, driver);
519
520         if (element_root != NULL)
521                 g_node_traverse(element_root, G_POST_ORDER,
522                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
523 }
524
525 static void unregister_property(gpointer data)
526 {
527         struct connman_property *property = data;
528
529         DBG("property %p", property);
530
531         g_free(property->value);
532         g_free(property);
533 }
534
535 static void unregister_child(gpointer data)
536 {
537         struct connman_element *element = data;
538
539         DBG("element %p", element);
540
541         connman_element_unref(element);
542 }
543
544 void __connman_element_initialize(struct connman_element *element)
545 {
546         DBG("element %p", element);
547
548         element->refcount = 1;
549
550         element->name    = NULL;
551         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
552         element->state   = CONNMAN_ELEMENT_STATE_UNKNOWN;
553         element->error   = CONNMAN_ELEMENT_ERROR_UNKNOWN;
554         element->index   = -1;
555         element->enabled = FALSE;
556
557         element->children = g_hash_table_new_full(g_str_hash, g_str_equal,
558                                                 NULL, unregister_child);
559
560         element->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
561                                                 g_free, unregister_property);
562 }
563
564 /**
565  * connman_element_create:
566  * @name: element name
567  *
568  * Allocate a new element and assign the given #name to it. If the name
569  * is #NULL, it will be later on created based on the element type.
570  *
571  * Returns: a newly-allocated #connman_element structure
572  */
573 struct connman_element *connman_element_create(const char *name)
574 {
575         struct connman_element *element;
576
577         element = g_try_new0(struct connman_element, 1);
578         if (element == NULL)
579                 return NULL;
580
581         DBG("element %p", element);
582
583         __connman_element_initialize(element);
584
585         element->name = g_strdup(name);
586
587         return element;
588 }
589
590 struct connman_element *connman_element_ref(struct connman_element *element)
591 {
592         DBG("element %p name %s refcount %d", element, element->name,
593                                 g_atomic_int_get(&element->refcount) + 1);
594
595         g_atomic_int_inc(&element->refcount);
596
597         return element;
598 }
599
600 static void free_properties(struct connman_element *element)
601 {
602         DBG("element %p name %s", element, element->name);
603
604         g_hash_table_destroy(element->properties);
605         element->properties = NULL;
606 }
607
608 static void free_children(struct connman_element *element)
609 {
610         DBG("element %p name %s", element, element->name);
611
612         g_hash_table_destroy(element->children);
613         element->children = NULL;
614 }
615
616 void connman_element_unref(struct connman_element *element)
617 {
618         DBG("element %p name %s refcount %d", element, element->name,
619                                 g_atomic_int_get(&element->refcount) - 1);
620
621         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
622                 if (element->destruct)
623                         element->destruct(element);
624                 free_children(element);
625                 free_properties(element);
626                 g_free(element->hostname);
627                 g_free(element->domainname);
628                 g_free(element->devname);
629                 g_free(element->path);
630                 g_free(element->name);
631                 g_free(element);
632         }
633 }
634
635 static int set_static_property(struct connman_element *element,
636                                 const char *name, int type, const void *value)
637 {
638         struct connman_property *property;
639
640         DBG("element %p name %s", element, element->name);
641
642         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
643                 return -EINVAL;
644
645         property = g_try_new0(struct connman_property, 1);
646         if (property == NULL)
647                 return -ENOMEM;
648
649         property->id   = CONNMAN_PROPERTY_ID_INVALID;
650         property->type = type;
651
652         DBG("name %s type %d value %p", name, type, value);
653
654         switch (type) {
655         case DBUS_TYPE_STRING:
656                 property->value = g_strdup(*((const char **) value));
657                 break;
658         case DBUS_TYPE_BOOLEAN:
659         case DBUS_TYPE_BYTE:
660                 property->value = g_try_malloc(1);
661                 if (property->value != NULL)
662                         memcpy(property->value, value, 1);
663                 break;
664         }
665
666         g_hash_table_replace(element->properties, g_strdup(name), property);
667
668         return 0;
669 }
670
671 static int set_static_array_property(struct connman_element *element,
672                         const char *name, int type, const void *value, int len)
673 {
674         struct connman_property *property;
675
676         DBG("element %p name %s", element, element->name);
677
678         if (type != DBUS_TYPE_BYTE)
679                 return -EINVAL;
680
681         property = g_try_new0(struct connman_property, 1);
682         if (property == NULL)
683                 return -ENOMEM;
684
685         property->id      = CONNMAN_PROPERTY_ID_INVALID;
686         property->type    = DBUS_TYPE_ARRAY;
687         property->subtype = type;
688
689         DBG("name %s type %d value %p", name, type, value);
690
691         switch (type) {
692         case DBUS_TYPE_BYTE:
693                 property->value = g_try_malloc(len);
694                 if (property->value != NULL) {
695                         memcpy(property->value,
696                                 *((const unsigned char **) value), len);
697                         property->size = len;
698                 }
699                 break;
700         }
701
702         g_hash_table_replace(element->properties, g_strdup(name), property);
703
704         return 0;
705 }
706
707 int connman_element_get_value(struct connman_element *element,
708                                 enum connman_property_id id, void *value)
709 {
710         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
711                 return -EINVAL;
712
713         switch (id) {
714         case CONNMAN_PROPERTY_ID_HOSTNAME:
715                 if (element->hostname == NULL)
716                         return connman_element_get_value(element->parent,
717                                                                 id, value);
718                 *((char **) value) = element->hostname;
719                 break;
720         case CONNMAN_PROPERTY_ID_DOMAINNAME:
721                 if (element->domainname == NULL)
722                         return connman_element_get_value(element->parent,
723                                                                 id, value);
724                 *((char **) value) = element->domainname;
725                 break;
726
727         default:
728                 return -EINVAL;
729         }
730
731         return 0;
732 }
733
734 static gboolean get_static_property(struct connman_element *element,
735                                                 const char *name, void *value)
736 {
737         struct connman_property *property;
738         gboolean found = FALSE;
739
740         DBG("element %p name %s", element, element->name);
741
742         property = g_hash_table_lookup(element->properties, name);
743         if (property != NULL) {
744                 switch (property->type) {
745                 case DBUS_TYPE_STRING:
746                         *((char **) value) = property->value;
747                         found = TRUE;
748                         break;
749                 case DBUS_TYPE_BOOLEAN:
750                 case DBUS_TYPE_BYTE:
751                         memcpy(value, property->value, 1);
752                         found = TRUE;
753                         break;
754                 }
755         }
756
757         if (found == FALSE && element->parent != NULL)
758                 return get_static_property(element->parent, name, value);
759
760         return found;
761 }
762
763 static gboolean get_static_array_property(struct connman_element *element,
764                         const char *name, void *value, unsigned int *len)
765 {
766         struct connman_property *property;
767         gboolean found = FALSE;
768
769         DBG("element %p name %s", element, element->name);
770
771         property = g_hash_table_lookup(element->properties, name);
772         if (property != NULL) {
773                 *((void **) value) = property->value;
774                 *len = property->size;
775                 found = TRUE;
776         }
777
778         return found;
779 }
780
781 /**
782  * connman_element_set_string:
783  * @element: element structure
784  * @key: unique identifier
785  * @value: string value
786  *
787  * Set string value for specific key
788  */
789 int connman_element_set_string(struct connman_element *element,
790                                         const char *key, const char *value)
791 {
792         return set_static_property(element, key, DBUS_TYPE_STRING, &value);
793 }
794
795 /**
796  * connman_element_get_string:
797  * @element: element structure
798  * @key: unique identifier
799  *
800  * Get string value for specific key
801  */
802 const char *connman_element_get_string(struct connman_element *element,
803                                                         const char *key)
804 {
805         const char *value;
806
807         if (get_static_property(element, key, &value) == FALSE)
808                 return NULL;
809
810         return value;
811 }
812
813 /**
814  * connman_element_set_bool:
815  * @element: element structure
816  * @key: unique identifier
817  * @value: boolean value
818  *
819  * Set boolean value for specific key
820  */
821 int connman_element_set_bool(struct connman_element *element,
822                                         const char *key, connman_bool_t value)
823 {
824         return set_static_property(element, key, DBUS_TYPE_BOOLEAN, &value);
825 }
826
827 /**
828  * connman_element_get_bool:
829  * @element: element structure
830  * @key: unique identifier
831  *
832  * Get boolean value for specific key
833  */
834 connman_bool_t connman_element_get_bool(struct connman_element *element,
835                                                         const char *key)
836 {
837         connman_bool_t value;
838
839         if (get_static_property(element, key, &value) == FALSE)
840                 return FALSE;
841
842         return value;
843 }
844
845 /**
846  * connman_element_set_uint8:
847  * @element: element structure
848  * @key: unique identifier
849  * @value: integer value
850  *
851  * Set integer value for specific key
852  */
853 int connman_element_set_uint8(struct connman_element *element,
854                                         const char *key, connman_uint8_t value)
855 {
856         return set_static_property(element, key, DBUS_TYPE_BYTE, &value);
857 }
858
859 /**
860  * connman_element_get_uint8:
861  * @element: element structure
862  * @key: unique identifier
863  *
864  * Get integer value for specific key
865  */
866 connman_uint8_t connman_element_get_uint8(struct connman_element *element,
867                                                         const char *key)
868 {
869         connman_uint8_t value;
870
871         if (get_static_property(element, key, &value) == FALSE)
872                 return 0;
873
874         return value;
875 }
876
877 /**
878  * connman_element_set_blob:
879  * @element: element structure
880  * @key: unique identifier
881  * @data: blob data
882  * @size: blob size
883  *
884  * Set binary blob value for specific key
885  */
886 int connman_element_set_blob(struct connman_element *element,
887                         const char *key, const void *data, unsigned int size)
888 {
889         return set_static_array_property(element, key,
890                                                 DBUS_TYPE_BYTE, &data, size);
891 }
892
893 /**
894  * connman_element_get_blob:
895  * @element: element structure
896  * @key: unique identifier
897  * @size: pointer to blob size
898  *
899  * Get binary blob value for specific key
900  */
901 const void *connman_element_get_blob(struct connman_element *element,
902                                         const char *key, unsigned int *size)
903 {
904         void *value;
905
906         if (get_static_array_property(element, key, &value, size) == FALSE)
907                 return NULL;
908
909         return value;
910 }
911
912 static void probe_element(struct connman_element *element)
913 {
914         GSList *list;
915
916         DBG("element %p name %s", element, element->name);
917
918         for (list = driver_list; list; list = list->next) {
919                 struct connman_driver *driver = list->data;
920
921                 if (match_driver(element, driver) == FALSE)
922                         continue;
923
924                 DBG("driver %p name %s", driver, driver->name);
925
926                 if (driver->probe(element) == 0) {
927                         element->driver = driver;
928                         break;
929                 }
930         }
931 }
932
933 static void register_element(gpointer data, gpointer user_data)
934 {
935         struct connman_element *element = data;
936         const gchar *basepath;
937         GNode *node;
938
939         if (element->parent) {
940                 node = g_node_find(element_root, G_PRE_ORDER,
941                                         G_TRAVERSE_ALL, element->parent);
942                 basepath = element->parent->path;
943         } else {
944                 element->parent = element_root->data;
945
946                 node = element_root;
947                 basepath = CONNMAN_PATH "/device";
948         }
949
950         element->path = g_strdup_printf("%s/%s", basepath, element->name);
951
952         if (node == NULL) {
953                 connman_error("Element registration for %s failed",
954                                                         element->path);
955                 return;
956         }
957
958         DBG("element %p path %s", element, element->path);
959
960         g_node_append_data(node, element);
961
962         if (started == FALSE)
963                 return;
964
965         probe_element(element);
966 }
967
968 gboolean __connman_element_device_isfiltered(const char *devname)
969 {
970         char **pattern;
971
972         if (device_filter == NULL)
973                 goto nodevice;
974
975         for (pattern = device_filter; *pattern; pattern++) {
976                 if (g_pattern_match_simple(*pattern, devname) == FALSE) {
977                         DBG("ignoring device %s (match)", devname);
978                         return TRUE;
979                 }
980         }
981
982 nodevice:
983         if (nodevice_filter == NULL)
984                 return FALSE;
985
986         for (pattern = nodevice_filter; *pattern; pattern++) {
987                 if (g_pattern_match_simple(*pattern, devname) == TRUE) {
988                         DBG("ignoring device %s (no match)", devname);
989                         return TRUE;
990                 }
991         }
992
993         return FALSE;
994 }
995
996 /**
997  * connman_element_register:
998  * @element: the element to register
999  * @parent: the parent to register the element with
1000  *
1001  * Register an element with the core. It will be register under the given
1002  * parent of if %NULL is provided under the root element.
1003  *
1004  * Returns: %0 on success
1005  */
1006 int connman_element_register(struct connman_element *element,
1007                                         struct connman_element *parent)
1008 {
1009         DBG("element %p name %s parent %p", element, element->name, parent);
1010
1011         if (element->devname == NULL)
1012                 element->devname = g_strdup(element->name);
1013
1014         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
1015                 goto setup;
1016
1017         if (__connman_element_device_isfiltered(element->devname) == TRUE)
1018                 return -EPERM;
1019
1020 setup:
1021         if (connman_element_ref(element) == NULL)
1022                 return -EINVAL;
1023
1024         if (element->name == NULL) {
1025                 element->name = g_strdup(type2string(element->type));
1026                 if (element->name == NULL) {
1027                         return -EINVAL;
1028                 }
1029         }
1030
1031         element->parent = parent;
1032
1033         register_element(element, NULL);
1034
1035         return 0;
1036 }
1037
1038 static gboolean remove_element(GNode *node, gpointer user_data)
1039 {
1040         struct connman_element *element = node->data;
1041         struct connman_element *root = user_data;
1042
1043         DBG("element %p name %s", element, element->name);
1044
1045         if (element == root)
1046                 return FALSE;
1047
1048         g_node_unlink(node);
1049
1050         if (element->driver) {
1051                 if (element->driver->remove)
1052                         element->driver->remove(element);
1053
1054                 element->driver = NULL;
1055         }
1056
1057         g_node_destroy(node);
1058
1059         connman_element_unref(element);
1060
1061         return FALSE;
1062 }
1063
1064 struct unregister_type {
1065         struct connman_element *root;
1066         enum connman_element_type type;
1067 };
1068
1069 static gboolean remove_element_type(GNode *node, gpointer user_data)
1070 {
1071         struct unregister_type *children_type = user_data;
1072         struct connman_element *root = children_type->root;
1073         struct connman_element *element = node->data;
1074         enum connman_element_type type = children_type->type;
1075
1076         DBG("element %p name %s", element, element->name);
1077
1078         if (element == root)
1079                 return FALSE;
1080
1081         if(element->type != type)
1082                 return FALSE;
1083
1084         g_node_unlink(node);
1085
1086         if (element->driver) {
1087                 if (element->driver->remove)
1088                         element->driver->remove(element);
1089
1090                 element->driver = NULL;
1091         }
1092
1093         g_node_destroy(node);
1094
1095         connman_element_unref(element);
1096
1097         return FALSE;
1098 }
1099
1100
1101 void connman_element_unregister(struct connman_element *element)
1102 {
1103         GNode *node;
1104
1105         DBG("element %p name %s", element, element->name);
1106
1107         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1108
1109         if (node != NULL)
1110                 g_node_traverse(node, G_POST_ORDER,
1111                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1112 }
1113
1114 void connman_element_unregister_children(struct connman_element *element)
1115 {
1116         GNode *node;
1117
1118         DBG("element %p name %s", element, element->name);
1119
1120         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1121
1122         if (node != NULL)
1123                 g_node_traverse(node, G_POST_ORDER,
1124                                 G_TRAVERSE_ALL, -1, remove_element, element);
1125 }
1126
1127 void connman_element_unregister_children_type(struct connman_element *element, enum connman_element_type type)
1128 {
1129         GNode *node;
1130
1131         DBG("element %p name %s", element, element->name);
1132
1133         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1134
1135         if (node != NULL) {
1136                 struct unregister_type children_type;
1137
1138                 children_type.root = element;
1139                 children_type.type = type;
1140                 g_node_traverse(node, G_POST_ORDER,
1141                                 G_TRAVERSE_ALL, -1, remove_element_type, &children_type);
1142         }
1143 }
1144
1145
1146 static gboolean update_element(GNode *node, gpointer user_data)
1147 {
1148         struct connman_element *element = node->data;
1149
1150         DBG("element %p name %s", element, element->name);
1151
1152         if (element->driver && element->driver->update)
1153                 element->driver->update(element);
1154
1155         return FALSE;
1156 }
1157
1158 void connman_element_update(struct connman_element *element)
1159 {
1160         GNode *node;
1161
1162         DBG("element %p name %s", element, element->name);
1163
1164         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1165
1166         if (node != NULL)
1167                 g_node_traverse(node, G_PRE_ORDER,
1168                                 G_TRAVERSE_ALL, -1, update_element, element);
1169 }
1170
1171 int connman_element_set_enabled(struct connman_element *element,
1172                                                         gboolean enabled)
1173 {
1174         if (element->enabled == enabled)
1175                 return 0;
1176
1177         element->enabled = enabled;
1178
1179         connman_element_update(element);
1180
1181         return 0;
1182 }
1183
1184 static enum connman_service_error convert_error(enum connman_element_error error)
1185 {
1186         return CONNMAN_SERVICE_ERROR_UNKNOWN;
1187 }
1188
1189 /**
1190  * connman_element_set_error:
1191  * @element: element structure
1192  * @error: error identifier
1193  *
1194  * Set error state and specific error identifier
1195  */
1196 void connman_element_set_error(struct connman_element *element,
1197                                         enum connman_element_error error)
1198 {
1199         struct connman_service *service;
1200
1201         DBG("element %p error %d", element, error);
1202
1203         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1204                 return;
1205
1206         element->state = CONNMAN_ELEMENT_STATE_ERROR;
1207         element->error = error;
1208
1209         if (element->driver && element->driver->change)
1210                 element->driver->change(element);
1211
1212         service = __connman_element_get_service(element);
1213         __connman_service_indicate_error(service, convert_error(error));
1214 }
1215
1216 void __connman_element_set_driver(struct connman_element *element)
1217 {
1218         GSList *list;
1219
1220         DBG("element %p name %s driver %p", element, element->name,
1221                                                 element->driver);
1222
1223         if (element->driver)
1224                 return;
1225
1226         for (list = driver_list; list; list = list->next) {
1227                 struct connman_driver *driver = list->data;
1228
1229                 if (match_driver(element, driver) == FALSE)
1230                         continue;
1231
1232                 element->driver = driver;
1233
1234                 break;
1235         }
1236 }
1237
1238 int __connman_element_init(const char *device, const char *nodevice)
1239 {
1240         struct connman_element *element;
1241
1242         DBG("");
1243
1244         connection = connman_dbus_get_connection();
1245         if (connection == NULL)
1246                 return -EIO;
1247
1248         if (device)
1249                 device_filter = g_strsplit(device, ",", -1);
1250
1251         if (nodevice)
1252                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1253
1254         element = connman_element_create("root");
1255
1256         element->path = g_strdup("/");
1257         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1258
1259         element_root = g_node_new(element);
1260
1261         __connman_technology_init();
1262         __connman_notifier_init();
1263         __connman_location_init();
1264         __connman_service_init();
1265         __connman_provider_init();
1266         __connman_network_init();
1267         __connman_device_init();
1268
1269         return 0;
1270 }
1271
1272 static gboolean probe_node(GNode *node, gpointer data)
1273 {
1274         struct connman_element *element = node->data;
1275
1276         DBG("element %p name %s", element, element->name);
1277
1278         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1279                 return FALSE;
1280
1281         if (element->driver)
1282                 return FALSE;
1283
1284         probe_element(element);
1285
1286         return FALSE;
1287 }
1288
1289 void __connman_element_start(void)
1290 {
1291         DBG("");
1292
1293         __connman_storage_init_profile();
1294
1295         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1296                                                         probe_node, NULL);
1297
1298         started = TRUE;
1299
1300         __connman_rtnl_start();
1301
1302         __connman_dhcp_init();
1303         __connman_wpad_init();
1304         __connman_wispr_init();
1305
1306         __connman_rfkill_init();
1307 }
1308
1309 void __connman_element_stop(void)
1310 {
1311         DBG("");
1312
1313         __connman_rfkill_cleanup();
1314
1315         __connman_wispr_cleanup();
1316         __connman_wpad_cleanup();
1317         __connman_dhcp_cleanup();
1318         __connman_provider_cleanup();
1319 }
1320
1321 static gboolean free_driver(GNode *node, gpointer data)
1322 {
1323         struct connman_element *element = node->data;
1324
1325         DBG("element %p name %s", element, element->name);
1326
1327         if (element->driver) {
1328                 if (element->driver->remove)
1329                         element->driver->remove(element);
1330
1331                 element->driver = NULL;
1332         }
1333
1334         return FALSE;
1335 }
1336
1337 static gboolean free_node(GNode *node, gpointer data)
1338 {
1339         struct connman_element *element = node->data;
1340
1341         DBG("element %p name %s", element, element->name);
1342
1343         if (g_node_depth(node) > 1)
1344                 connman_element_unregister(element);
1345
1346         return FALSE;
1347 }
1348
1349 void __connman_element_cleanup(void)
1350 {
1351         DBG("");
1352
1353         __connman_device_cleanup();
1354         __connman_network_cleanup();
1355         __connman_service_cleanup();
1356         __connman_location_cleanup();
1357         __connman_notifier_cleanup();
1358         __connman_technology_cleanup();
1359
1360         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1361                                                         free_driver, NULL);
1362
1363         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1364                                                         free_node, NULL);
1365
1366         connman_element_unref(element_root->data);
1367
1368         g_node_destroy(element_root);
1369         element_root = NULL;
1370
1371         g_strfreev(nodevice_filter);
1372         g_strfreev(device_filter);
1373
1374         if (connection == NULL)
1375                 return;
1376
1377         dbus_connection_unref(connection);
1378 }