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