af9bcdce23ecc37844582536bf8576675449590e
[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->ipv6.address);
629                 g_free(element->ipv6.network);
630                 g_free(element->devname);
631                 g_free(element->path);
632                 g_free(element->name);
633                 g_free(element);
634         }
635 }
636
637 static int set_static_property(struct connman_element *element,
638                                 const char *name, int type, const void *value)
639 {
640         struct connman_property *property;
641
642         DBG("element %p name %s", element, element->name);
643
644         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
645                 return -EINVAL;
646
647         property = g_try_new0(struct connman_property, 1);
648         if (property == NULL)
649                 return -ENOMEM;
650
651         property->id   = CONNMAN_PROPERTY_ID_INVALID;
652         property->type = type;
653
654         DBG("name %s type %d value %p", name, type, value);
655
656         switch (type) {
657         case DBUS_TYPE_STRING:
658                 property->value = g_strdup(*((const char **) value));
659                 break;
660         case DBUS_TYPE_BOOLEAN:
661         case DBUS_TYPE_BYTE:
662                 property->value = g_try_malloc(1);
663                 if (property->value != NULL)
664                         memcpy(property->value, value, 1);
665                 break;
666         }
667
668         g_hash_table_replace(element->properties, g_strdup(name), property);
669
670         return 0;
671 }
672
673 static int set_static_array_property(struct connman_element *element,
674                         const char *name, int type, const void *value, int len)
675 {
676         struct connman_property *property;
677
678         DBG("element %p name %s", element, element->name);
679
680         if (type != DBUS_TYPE_BYTE)
681                 return -EINVAL;
682
683         property = g_try_new0(struct connman_property, 1);
684         if (property == NULL)
685                 return -ENOMEM;
686
687         property->id      = CONNMAN_PROPERTY_ID_INVALID;
688         property->type    = DBUS_TYPE_ARRAY;
689         property->subtype = type;
690
691         DBG("name %s type %d value %p", name, type, value);
692
693         switch (type) {
694         case DBUS_TYPE_BYTE:
695                 property->value = g_try_malloc(len);
696                 if (property->value != NULL) {
697                         memcpy(property->value,
698                                 *((const unsigned char **) value), len);
699                         property->size = len;
700                 }
701                 break;
702         }
703
704         g_hash_table_replace(element->properties, g_strdup(name), property);
705
706         return 0;
707 }
708
709 int connman_element_get_value(struct connman_element *element,
710                                 enum connman_property_id id, void *value)
711 {
712         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
713                 return -EINVAL;
714
715         switch (id) {
716         case CONNMAN_PROPERTY_ID_HOSTNAME:
717                 if (element->hostname == NULL)
718                         return connman_element_get_value(element->parent,
719                                                                 id, value);
720                 *((char **) value) = element->hostname;
721                 break;
722         case CONNMAN_PROPERTY_ID_DOMAINNAME:
723                 if (element->domainname == NULL)
724                         return connman_element_get_value(element->parent,
725                                                                 id, value);
726                 *((char **) value) = element->domainname;
727                 break;
728         case CONNMAN_PROPERTY_ID_IPV6_GATEWAY:
729                 if (element->ipv6.gateway == NULL)
730                         return connman_element_get_value(element->parent,
731                                                                 id, value);
732                 *((char **) value) = element->ipv6.gateway;
733                 break;
734
735         default:
736                 return -EINVAL;
737         }
738
739         return 0;
740 }
741
742 static gboolean get_static_property(struct connman_element *element,
743                                                 const char *name, void *value)
744 {
745         struct connman_property *property;
746         gboolean found = FALSE;
747
748         DBG("element %p name %s", element, element->name);
749
750         property = g_hash_table_lookup(element->properties, name);
751         if (property != NULL) {
752                 switch (property->type) {
753                 case DBUS_TYPE_STRING:
754                         *((char **) value) = property->value;
755                         found = TRUE;
756                         break;
757                 case DBUS_TYPE_BOOLEAN:
758                 case DBUS_TYPE_BYTE:
759                         memcpy(value, property->value, 1);
760                         found = TRUE;
761                         break;
762                 }
763         }
764
765         if (found == FALSE && element->parent != NULL)
766                 return get_static_property(element->parent, name, value);
767
768         return found;
769 }
770
771 static gboolean get_static_array_property(struct connman_element *element,
772                         const char *name, void *value, unsigned int *len)
773 {
774         struct connman_property *property;
775         gboolean found = FALSE;
776
777         DBG("element %p name %s", element, element->name);
778
779         property = g_hash_table_lookup(element->properties, name);
780         if (property != NULL) {
781                 *((void **) value) = property->value;
782                 *len = property->size;
783                 found = TRUE;
784         }
785
786         return found;
787 }
788
789 /**
790  * connman_element_set_string:
791  * @element: element structure
792  * @key: unique identifier
793  * @value: string value
794  *
795  * Set string value for specific key
796  */
797 int connman_element_set_string(struct connman_element *element,
798                                         const char *key, const char *value)
799 {
800         return set_static_property(element, key, DBUS_TYPE_STRING, &value);
801 }
802
803 /**
804  * connman_element_get_string:
805  * @element: element structure
806  * @key: unique identifier
807  *
808  * Get string value for specific key
809  */
810 const char *connman_element_get_string(struct connman_element *element,
811                                                         const char *key)
812 {
813         const char *value;
814
815         if (get_static_property(element, key, &value) == FALSE)
816                 return NULL;
817
818         return value;
819 }
820
821 /**
822  * connman_element_set_bool:
823  * @element: element structure
824  * @key: unique identifier
825  * @value: boolean value
826  *
827  * Set boolean value for specific key
828  */
829 int connman_element_set_bool(struct connman_element *element,
830                                         const char *key, connman_bool_t value)
831 {
832         return set_static_property(element, key, DBUS_TYPE_BOOLEAN, &value);
833 }
834
835 /**
836  * connman_element_get_bool:
837  * @element: element structure
838  * @key: unique identifier
839  *
840  * Get boolean value for specific key
841  */
842 connman_bool_t connman_element_get_bool(struct connman_element *element,
843                                                         const char *key)
844 {
845         connman_bool_t value;
846
847         if (get_static_property(element, key, &value) == FALSE)
848                 return FALSE;
849
850         return value;
851 }
852
853 /**
854  * connman_element_set_uint8:
855  * @element: element structure
856  * @key: unique identifier
857  * @value: integer value
858  *
859  * Set integer value for specific key
860  */
861 int connman_element_set_uint8(struct connman_element *element,
862                                         const char *key, connman_uint8_t value)
863 {
864         return set_static_property(element, key, DBUS_TYPE_BYTE, &value);
865 }
866
867 /**
868  * connman_element_get_uint8:
869  * @element: element structure
870  * @key: unique identifier
871  *
872  * Get integer value for specific key
873  */
874 connman_uint8_t connman_element_get_uint8(struct connman_element *element,
875                                                         const char *key)
876 {
877         connman_uint8_t value;
878
879         if (get_static_property(element, key, &value) == FALSE)
880                 return 0;
881
882         return value;
883 }
884
885 /**
886  * connman_element_set_blob:
887  * @element: element structure
888  * @key: unique identifier
889  * @data: blob data
890  * @size: blob size
891  *
892  * Set binary blob value for specific key
893  */
894 int connman_element_set_blob(struct connman_element *element,
895                         const char *key, const void *data, unsigned int size)
896 {
897         return set_static_array_property(element, key,
898                                                 DBUS_TYPE_BYTE, &data, size);
899 }
900
901 /**
902  * connman_element_get_blob:
903  * @element: element structure
904  * @key: unique identifier
905  * @size: pointer to blob size
906  *
907  * Get binary blob value for specific key
908  */
909 const void *connman_element_get_blob(struct connman_element *element,
910                                         const char *key, unsigned int *size)
911 {
912         void *value;
913
914         if (get_static_array_property(element, key, &value, size) == FALSE)
915                 return NULL;
916
917         return value;
918 }
919
920 static void probe_element(struct connman_element *element)
921 {
922         GSList *list;
923
924         DBG("element %p name %s", element, element->name);
925
926         for (list = driver_list; list; list = list->next) {
927                 struct connman_driver *driver = list->data;
928
929                 if (match_driver(element, driver) == FALSE)
930                         continue;
931
932                 DBG("driver %p name %s", driver, driver->name);
933
934                 if (driver->probe(element) == 0) {
935                         element->driver = driver;
936                         break;
937                 }
938         }
939 }
940
941 static void register_element(gpointer data, gpointer user_data)
942 {
943         struct connman_element *element = data;
944         const gchar *basepath;
945         GNode *node;
946
947         if (element->parent) {
948                 node = g_node_find(element_root, G_PRE_ORDER,
949                                         G_TRAVERSE_ALL, element->parent);
950                 basepath = element->parent->path;
951         } else {
952                 element->parent = element_root->data;
953
954                 node = element_root;
955                 basepath = CONNMAN_PATH "/device";
956         }
957
958         element->path = g_strdup_printf("%s/%s", basepath, element->name);
959
960         if (node == NULL) {
961                 connman_error("Element registration for %s failed",
962                                                         element->path);
963                 return;
964         }
965
966         DBG("element %p path %s", element, element->path);
967
968         g_node_append_data(node, element);
969
970         if (started == FALSE)
971                 return;
972
973         probe_element(element);
974 }
975
976 gboolean __connman_element_device_isfiltered(const char *devname)
977 {
978         char **pattern;
979
980         if (device_filter == NULL)
981                 goto nodevice;
982
983         for (pattern = device_filter; *pattern; pattern++) {
984                 if (g_pattern_match_simple(*pattern, devname) == FALSE) {
985                         DBG("ignoring device %s (match)", devname);
986                         return TRUE;
987                 }
988         }
989
990 nodevice:
991         if (nodevice_filter == NULL)
992                 return FALSE;
993
994         for (pattern = nodevice_filter; *pattern; pattern++) {
995                 if (g_pattern_match_simple(*pattern, devname) == TRUE) {
996                         DBG("ignoring device %s (no match)", devname);
997                         return TRUE;
998                 }
999         }
1000
1001         return FALSE;
1002 }
1003
1004 /**
1005  * connman_element_register:
1006  * @element: the element to register
1007  * @parent: the parent to register the element with
1008  *
1009  * Register an element with the core. It will be register under the given
1010  * parent of if %NULL is provided under the root element.
1011  *
1012  * Returns: %0 on success
1013  */
1014 int connman_element_register(struct connman_element *element,
1015                                         struct connman_element *parent)
1016 {
1017         DBG("element %p name %s parent %p", element, element->name, parent);
1018
1019         if (element->devname == NULL)
1020                 element->devname = g_strdup(element->name);
1021
1022         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
1023                 goto setup;
1024
1025         if (__connman_element_device_isfiltered(element->devname) == TRUE)
1026                 return -EPERM;
1027
1028 setup:
1029         if (connman_element_ref(element) == NULL)
1030                 return -EINVAL;
1031
1032         if (element->name == NULL) {
1033                 element->name = g_strdup(type2string(element->type));
1034                 if (element->name == NULL) {
1035                         return -EINVAL;
1036                 }
1037         }
1038
1039         element->parent = parent;
1040
1041         register_element(element, NULL);
1042
1043         return 0;
1044 }
1045
1046 static gboolean remove_element(GNode *node, gpointer user_data)
1047 {
1048         struct connman_element *element = node->data;
1049         struct connman_element *root = user_data;
1050
1051         DBG("element %p name %s", element, element->name);
1052
1053         if (element == root)
1054                 return FALSE;
1055
1056         g_node_unlink(node);
1057
1058         if (element->driver) {
1059                 if (element->driver->remove)
1060                         element->driver->remove(element);
1061
1062                 element->driver = NULL;
1063         }
1064
1065         g_node_destroy(node);
1066
1067         connman_element_unref(element);
1068
1069         return FALSE;
1070 }
1071
1072 struct unregister_type {
1073         struct connman_element *root;
1074         enum connman_element_type type;
1075 };
1076
1077 static gboolean remove_element_type(GNode *node, gpointer user_data)
1078 {
1079         struct unregister_type *children_type = user_data;
1080         struct connman_element *root = children_type->root;
1081         struct connman_element *element = node->data;
1082         enum connman_element_type type = children_type->type;
1083
1084         DBG("element %p name %s", element, element->name);
1085
1086         if (element == root)
1087                 return FALSE;
1088
1089         if(element->type != type)
1090                 return FALSE;
1091
1092         g_node_unlink(node);
1093
1094         if (element->driver) {
1095                 if (element->driver->remove)
1096                         element->driver->remove(element);
1097
1098                 element->driver = NULL;
1099         }
1100
1101         g_node_destroy(node);
1102
1103         connman_element_unref(element);
1104
1105         return FALSE;
1106 }
1107
1108
1109 void connman_element_unregister(struct connman_element *element)
1110 {
1111         GNode *node;
1112
1113         DBG("element %p name %s", element, element->name);
1114
1115         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1116
1117         if (node != NULL)
1118                 g_node_traverse(node, G_POST_ORDER,
1119                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1120 }
1121
1122 void connman_element_unregister_children(struct connman_element *element)
1123 {
1124         GNode *node;
1125
1126         DBG("element %p name %s", element, element->name);
1127
1128         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1129
1130         if (node != NULL)
1131                 g_node_traverse(node, G_POST_ORDER,
1132                                 G_TRAVERSE_ALL, -1, remove_element, element);
1133 }
1134
1135 void connman_element_unregister_children_type(struct connman_element *element, enum connman_element_type type)
1136 {
1137         GNode *node;
1138
1139         DBG("element %p name %s", element, element->name);
1140
1141         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1142
1143         if (node != NULL) {
1144                 struct unregister_type children_type;
1145
1146                 children_type.root = element;
1147                 children_type.type = type;
1148                 g_node_traverse(node, G_POST_ORDER,
1149                                 G_TRAVERSE_ALL, -1, remove_element_type, &children_type);
1150         }
1151 }
1152
1153
1154 static gboolean update_element(GNode *node, gpointer user_data)
1155 {
1156         struct connman_element *element = node->data;
1157
1158         DBG("element %p name %s", element, element->name);
1159
1160         if (element->driver && element->driver->update)
1161                 element->driver->update(element);
1162
1163         return FALSE;
1164 }
1165
1166 void connman_element_update(struct connman_element *element)
1167 {
1168         GNode *node;
1169
1170         DBG("element %p name %s", element, element->name);
1171
1172         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1173
1174         if (node != NULL)
1175                 g_node_traverse(node, G_PRE_ORDER,
1176                                 G_TRAVERSE_ALL, -1, update_element, element);
1177 }
1178
1179 int connman_element_set_enabled(struct connman_element *element,
1180                                                         gboolean enabled)
1181 {
1182         if (element->enabled == enabled)
1183                 return 0;
1184
1185         element->enabled = enabled;
1186
1187         connman_element_update(element);
1188
1189         return 0;
1190 }
1191
1192 static enum connman_service_error convert_error(enum connman_element_error error)
1193 {
1194         switch (error) {
1195         case CONNMAN_ELEMENT_ERROR_UNKNOWN:
1196         case CONNMAN_ELEMENT_ERROR_FAILED:
1197                 break;
1198         case CONNMAN_ELEMENT_ERROR_CONNECT_FAILED:
1199                 return CONNMAN_SERVICE_ERROR_CONNECT_FAILED;
1200         }
1201
1202         return CONNMAN_SERVICE_ERROR_UNKNOWN;
1203 }
1204
1205 /**
1206  * connman_element_set_error:
1207  * @element: element structure
1208  * @error: error identifier
1209  *
1210  * Set error state and specific error identifier
1211  */
1212 void connman_element_set_error(struct connman_element *element,
1213                                         enum connman_element_error error)
1214 {
1215         struct connman_service *service;
1216
1217         DBG("element %p error %d", element, error);
1218
1219         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1220                 return;
1221
1222         element->state = CONNMAN_ELEMENT_STATE_ERROR;
1223         element->error = error;
1224
1225         if (element->driver && element->driver->change)
1226                 element->driver->change(element);
1227
1228         service = __connman_element_get_service(element);
1229         __connman_service_indicate_error(service, convert_error(error));
1230 }
1231
1232 void __connman_element_set_driver(struct connman_element *element)
1233 {
1234         GSList *list;
1235
1236         DBG("element %p name %s driver %p", element, element->name,
1237                                                 element->driver);
1238
1239         if (element->driver)
1240                 return;
1241
1242         for (list = driver_list; list; list = list->next) {
1243                 struct connman_driver *driver = list->data;
1244
1245                 if (match_driver(element, driver) == FALSE)
1246                         continue;
1247
1248                 element->driver = driver;
1249
1250                 break;
1251         }
1252 }
1253
1254 int __connman_element_init(const char *device, const char *nodevice)
1255 {
1256         struct connman_element *element;
1257
1258         DBG("");
1259
1260         connection = connman_dbus_get_connection();
1261         if (connection == NULL)
1262                 return -EIO;
1263
1264         if (device)
1265                 device_filter = g_strsplit(device, ",", -1);
1266
1267         if (nodevice)
1268                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1269
1270         element = connman_element_create("root");
1271
1272         element->path = g_strdup("/");
1273         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1274
1275         element_root = g_node_new(element);
1276
1277         __connman_technology_init();
1278         __connman_notifier_init();
1279         __connman_location_init();
1280         __connman_service_init();
1281         __connman_provider_init();
1282         __connman_network_init();
1283         __connman_device_init();
1284
1285         return 0;
1286 }
1287
1288 static gboolean probe_node(GNode *node, gpointer data)
1289 {
1290         struct connman_element *element = node->data;
1291
1292         DBG("element %p name %s", element, element->name);
1293
1294         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1295                 return FALSE;
1296
1297         if (element->driver)
1298                 return FALSE;
1299
1300         probe_element(element);
1301
1302         return FALSE;
1303 }
1304
1305 void __connman_element_start(void)
1306 {
1307         DBG("");
1308
1309         __connman_storage_init_profile();
1310
1311         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1312                                                         probe_node, NULL);
1313
1314         started = TRUE;
1315
1316         __connman_rtnl_start();
1317
1318         __connman_dhcp_init();
1319         __connman_wpad_init();
1320         __connman_wispr_init();
1321
1322         __connman_rfkill_init();
1323 }
1324
1325 void __connman_element_stop(void)
1326 {
1327         DBG("");
1328
1329         __connman_rfkill_cleanup();
1330
1331         __connman_wispr_cleanup();
1332         __connman_wpad_cleanup();
1333         __connman_dhcp_cleanup();
1334         __connman_provider_cleanup();
1335 }
1336
1337 static gboolean free_driver(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 (element->driver) {
1344                 if (element->driver->remove)
1345                         element->driver->remove(element);
1346
1347                 element->driver = NULL;
1348         }
1349
1350         return FALSE;
1351 }
1352
1353 static gboolean free_node(GNode *node, gpointer data)
1354 {
1355         struct connman_element *element = node->data;
1356
1357         DBG("element %p name %s", element, element->name);
1358
1359         if (g_node_depth(node) > 1)
1360                 connman_element_unregister(element);
1361
1362         return FALSE;
1363 }
1364
1365 void __connman_element_cleanup(void)
1366 {
1367         DBG("");
1368
1369         __connman_device_cleanup();
1370         __connman_network_cleanup();
1371         __connman_service_cleanup();
1372         __connman_location_cleanup();
1373         __connman_notifier_cleanup();
1374         __connman_technology_cleanup();
1375
1376         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1377                                                         free_driver, NULL);
1378
1379         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1380                                                         free_node, NULL);
1381
1382         connman_element_unref(element_root->data);
1383
1384         g_node_destroy(element_root);
1385         element_root = NULL;
1386
1387         g_strfreev(nodevice_filter);
1388         g_strfreev(device_filter);
1389
1390         if (connection == NULL)
1391                 return;
1392
1393         dbus_connection_unref(connection);
1394 }