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