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