Add support for exporting Broadcast and Nameserver properties
[platform/upstream/connman.git] / 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 static struct connman_network *__connman_element_get_network(struct connman_element *element)
276 {
277         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
278                                                 element->network != NULL)
279                 return element->network;
280
281         if (element->parent == NULL)
282                 return NULL;
283
284         return __connman_element_get_network(element->parent);
285 }
286
287 struct connman_service *__connman_element_get_service(struct connman_element *element)
288 {
289         struct connman_service *service = NULL;
290         struct connman_network *network;
291         struct connman_device *device;
292         enum connman_device_type type;
293
294         device = __connman_element_get_device(element);
295         if (device == NULL)
296                 return NULL;
297
298         type = connman_device_get_type(device);
299
300         switch (type) {
301         case CONNMAN_DEVICE_TYPE_UNKNOWN:
302         case CONNMAN_DEVICE_TYPE_VENDOR:
303         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
304         case CONNMAN_DEVICE_TYPE_GPS:
305         case CONNMAN_DEVICE_TYPE_HSO:
306         case CONNMAN_DEVICE_TYPE_NOZOMI:
307         case CONNMAN_DEVICE_TYPE_HUAWEI:
308         case CONNMAN_DEVICE_TYPE_NOVATEL:
309                 break;
310         case CONNMAN_DEVICE_TYPE_ETHERNET:
311                 service = __connman_service_lookup_from_device(device);
312                 break;
313         case CONNMAN_DEVICE_TYPE_WIFI:
314         case CONNMAN_DEVICE_TYPE_WIMAX:
315                 network = __connman_element_get_network(element);
316                 if (network == NULL)
317                         return NULL;
318                 service = __connman_service_lookup_from_network(network);
319                 break;
320         }
321
322         return service;
323 }
324
325 struct connman_device *__connman_element_get_device(struct connman_element *element)
326 {
327         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
328                                                 element->device != NULL)
329                 return element->device;
330
331         if (element->parent == NULL)
332                 return NULL;
333
334         return __connman_element_get_device(element->parent);
335 }
336
337 const char *__connman_element_get_device_path(struct connman_element *element)
338 {
339         struct connman_device *device;
340
341         device = __connman_element_get_device(element);
342         if (device == NULL)
343                 return NULL;
344
345         return connman_device_get_path(device);
346 }
347
348 const char *__connman_element_get_network_path(struct connman_element *element)
349 {
350         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
351                                                 element->network != NULL)
352                 return element->path;
353
354         if (element->parent == NULL)
355                 return NULL;
356
357         return __connman_element_get_network_path(element->parent);
358 }
359
360 static gint compare_priority(gconstpointer a, gconstpointer b)
361 {
362         const struct connman_driver *driver1 = a;
363         const struct connman_driver *driver2 = b;
364
365         return driver2->priority - driver1->priority;
366 }
367
368 static gboolean match_driver(struct connman_element *element,
369                                         struct connman_driver *driver)
370 {
371         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
372                 return FALSE;
373
374         if (element->type == driver->type ||
375                         driver->type == CONNMAN_ELEMENT_TYPE_UNKNOWN)
376                 return TRUE;
377
378         return FALSE;
379 }
380
381 static gboolean probe_driver(GNode *node, gpointer data)
382 {
383         struct connman_element *element = node->data;
384         struct connman_driver *driver = data;
385
386         DBG("element %p name %s", element, element->name);
387
388         if (!element->driver && match_driver(element, driver) == TRUE) {
389                 if (driver->probe(element) < 0)
390                         return FALSE;
391
392                 __connman_element_lock(element);
393                 element->driver = driver;
394                 __connman_element_unlock(element);
395         }
396
397         return FALSE;
398 }
399
400 void __connman_driver_rescan(struct connman_driver *driver)
401 {
402         DBG("driver %p name %s", driver, driver->name);
403
404         if (!driver->probe)
405                 return;
406
407         if (element_root != NULL)
408                 g_node_traverse(element_root, G_PRE_ORDER,
409                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
410 }
411
412 /**
413  * connman_driver_register:
414  * @driver: driver definition
415  *
416  * Register a new driver
417  *
418  * Returns: %0 on success
419  */
420 int connman_driver_register(struct connman_driver *driver)
421 {
422         DBG("driver %p name %s", driver, driver->name);
423
424         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
425                 return -EINVAL;
426
427         if (!driver->probe)
428                 return -EINVAL;
429
430         driver_list = g_slist_insert_sorted(driver_list, driver,
431                                                         compare_priority);
432
433         if (started == FALSE)
434                 return 0;
435
436         if (element_root != NULL)
437                 g_node_traverse(element_root, G_PRE_ORDER,
438                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
439
440         return 0;
441 }
442
443 static gboolean remove_driver(GNode *node, gpointer data)
444 {
445         struct connman_element *element = node->data;
446         struct connman_driver *driver = data;
447
448         DBG("element %p name %s", element, element->name);
449
450         if (element->driver == driver) {
451                 if (driver->remove)
452                         driver->remove(element);
453
454                 __connman_element_lock(element);
455                 element->driver = NULL;
456                 __connman_element_unlock(element);
457         }
458
459         return FALSE;
460 }
461
462 /**
463  * connman_driver_unregister:
464  * @driver: driver definition
465  *
466  * Remove a previously registered driver
467  */
468 void connman_driver_unregister(struct connman_driver *driver)
469 {
470         DBG("driver %p name %s", driver, driver->name);
471
472         driver_list = g_slist_remove(driver_list, driver);
473
474         if (element_root != NULL)
475                 g_node_traverse(element_root, G_POST_ORDER,
476                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
477 }
478
479 static void unregister_property(gpointer data)
480 {
481         struct connman_property *property = data;
482
483         DBG("property %p", property);
484
485         g_free(property->value);
486         g_free(property);
487 }
488
489 void __connman_element_initialize(struct connman_element *element)
490 {
491         DBG("element %p", element);
492
493         element->refcount = 1;
494
495         element->name    = NULL;
496         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
497         element->state   = CONNMAN_ELEMENT_STATE_UNKNOWN;
498         element->error   = CONNMAN_ELEMENT_ERROR_UNKNOWN;
499         element->index   = -1;
500         element->enabled = FALSE;
501
502         element->configuring = FALSE;
503
504         element->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
505                                                 g_free, unregister_property);
506 }
507
508 /**
509  * connman_element_create:
510  * @name: element name
511  *
512  * Allocate a new element and assign the given #name to it. If the name
513  * is #NULL, it will be later on created based on the element type.
514  *
515  * Returns: a newly-allocated #connman_element structure
516  */
517 struct connman_element *connman_element_create(const char *name)
518 {
519         struct connman_element *element;
520
521         element = g_try_new0(struct connman_element, 1);
522         if (element == NULL)
523                 return NULL;
524
525         DBG("element %p", element);
526
527         __connman_element_initialize(element);
528
529         return element;
530 }
531
532 struct connman_element *connman_element_ref(struct connman_element *element)
533 {
534         DBG("element %p name %s refcount %d", element, element->name,
535                                 g_atomic_int_get(&element->refcount) + 1);
536
537         g_atomic_int_inc(&element->refcount);
538
539         return element;
540 }
541
542 static void free_properties(struct connman_element *element)
543 {
544         DBG("element %p name %s", element, element->name);
545
546         __connman_element_lock(element);
547
548         g_hash_table_destroy(element->properties);
549         element->properties = NULL;
550
551         __connman_element_unlock(element);
552 }
553
554 void connman_element_unref(struct connman_element *element)
555 {
556         DBG("element %p name %s refcount %d", element, element->name,
557                                 g_atomic_int_get(&element->refcount) - 1);
558
559         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
560                 if (element->destruct)
561                         element->destruct(element);
562                 free_properties(element);
563                 g_free(element->ipv4.address);
564                 g_free(element->ipv4.netmask);
565                 g_free(element->ipv4.gateway);
566                 g_free(element->ipv4.network);
567                 g_free(element->ipv4.broadcast);
568                 g_free(element->ipv4.nameserver);
569                 g_free(element->devname);
570                 g_free(element->path);
571                 g_free(element->name);
572                 g_free(element);
573         }
574 }
575
576 static int set_static_property(struct connman_element *element,
577                                 const char *name, int type, const void *value)
578 {
579         struct connman_property *property;
580
581         DBG("element %p name %s", element, element->name);
582
583         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
584                 return -EINVAL;
585
586         property = g_try_new0(struct connman_property, 1);
587         if (property == NULL)
588                 return -ENOMEM;
589
590         property->id   = CONNMAN_PROPERTY_ID_INVALID;
591         property->type = type;
592
593         DBG("name %s type %d value %p", name, type, value);
594
595         switch (type) {
596         case DBUS_TYPE_STRING:
597                 property->value = g_strdup(*((const char **) value));
598                 break;
599         case DBUS_TYPE_BYTE:
600                 property->value = g_try_malloc(1);
601                 if (property->value != NULL)
602                         memcpy(property->value, value, 1);
603                 break;
604         }
605
606         __connman_element_lock(element);
607
608         g_hash_table_replace(element->properties, g_strdup(name), property);
609
610         __connman_element_unlock(element);
611
612         return 0;
613 }
614
615 static int set_static_array_property(struct connman_element *element,
616                         const char *name, int type, const void *value, int len)
617 {
618         struct connman_property *property;
619
620         DBG("element %p name %s", element, element->name);
621
622         if (type != DBUS_TYPE_BYTE)
623                 return -EINVAL;
624
625         property = g_try_new0(struct connman_property, 1);
626         if (property == NULL)
627                 return -ENOMEM;
628
629         property->id      = CONNMAN_PROPERTY_ID_INVALID;
630         property->type    = DBUS_TYPE_ARRAY;
631         property->subtype = type;
632
633         DBG("name %s type %d value %p", name, type, value);
634
635         switch (type) {
636         case DBUS_TYPE_BYTE:
637                 property->value = g_try_malloc(len);
638                 if (property->value != NULL) {
639                         memcpy(property->value,
640                                 *((const unsigned char **) value), len);
641                         property->size = len;
642                 }
643                 break;
644         }
645
646         __connman_element_lock(element);
647
648         g_hash_table_replace(element->properties, g_strdup(name), property);
649
650         __connman_element_unlock(element);
651
652         return 0;
653 }
654
655 #if 0
656 static int set_property(struct connman_element *element,
657                                 enum connman_property_id id, const void *value)
658 {
659         switch (id) {
660         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
661                 __connman_element_lock(element);
662                 g_free(element->ipv4.address);
663                 element->ipv4.address = g_strdup(*((const char **) value));
664                 __connman_element_unlock(element);
665                 break;
666         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
667                 __connman_element_lock(element);
668                 g_free(element->ipv4.netmask);
669                 element->ipv4.netmask = g_strdup(*((const char **) value));
670                 __connman_element_unlock(element);
671                 break;
672         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
673                 __connman_element_lock(element);
674                 g_free(element->ipv4.gateway);
675                 element->ipv4.gateway = g_strdup(*((const char **) value));
676                 __connman_element_unlock(element);
677                 break;
678         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
679                 __connman_element_lock(element);
680                 g_free(element->ipv4.broadcast);
681                 element->ipv4.broadcast = g_strdup(*((const char **) value));
682                 __connman_element_unlock(element);
683                 break;
684         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
685                 __connman_element_lock(element);
686                 g_free(element->ipv4.nameserver);
687                 element->ipv4.nameserver = g_strdup(*((const char **) value));
688                 __connman_element_unlock(element);
689                 break;
690         default:
691                 return -EINVAL;
692         }
693
694         return 0;
695 }
696 #endif
697
698 int connman_element_get_value(struct connman_element *element,
699                                 enum connman_property_id id, void *value)
700 {
701         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
702                 return -EINVAL;
703
704         switch (id) {
705         case CONNMAN_PROPERTY_ID_IPV4_METHOD:
706                 if (element->ipv4.method == CONNMAN_IPV4_METHOD_UNKNOWN)
707                         return connman_element_get_value(element->parent,
708                                                                 id, value);
709                 __connman_element_lock(element);
710                 *((const char **) value) = __connman_ipv4_method2string(element->ipv4.method);
711                 __connman_element_unlock(element);
712                 break;
713         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
714                 if (element->ipv4.address == NULL)
715                         return connman_element_get_value(element->parent,
716                                                                 id, value);
717                 __connman_element_lock(element);
718                 *((char **) value) = element->ipv4.address;
719                 __connman_element_unlock(element);
720                 break;
721         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
722                 if (element->ipv4.netmask == NULL)
723                         return connman_element_get_value(element->parent,
724                                                                 id, value);
725                 __connman_element_lock(element);
726                 *((char **) value) = element->ipv4.netmask;
727                 __connman_element_unlock(element);
728                 break;
729         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
730                 if (element->ipv4.gateway == NULL)
731                         return connman_element_get_value(element->parent,
732                                                                 id, value);
733                 __connman_element_lock(element);
734                 *((char **) value) = element->ipv4.gateway;
735                 __connman_element_unlock(element);
736                 break;
737         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
738                 if (element->ipv4.broadcast == NULL)
739                         return connman_element_get_value(element->parent,
740                                                                 id, value);
741                 __connman_element_lock(element);
742                 *((char **) value) = element->ipv4.broadcast;
743                 __connman_element_unlock(element);
744                 break;
745         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
746                 if (element->ipv4.nameserver == NULL)
747                         return connman_element_get_value(element->parent,
748                                                                 id, value);
749                 __connman_element_lock(element);
750                 *((char **) value) = element->ipv4.nameserver;
751                 __connman_element_unlock(element);
752                 break;
753         default:
754                 return -EINVAL;
755         }
756
757         return 0;
758 }
759
760 static gboolean get_static_property(struct connman_element *element,
761                                                 const char *name, void *value)
762 {
763         struct connman_property *property;
764         gboolean found = FALSE;
765
766         DBG("element %p name %s", element, element->name);
767
768         __connman_element_lock(element);
769
770         property = g_hash_table_lookup(element->properties, name);
771         if (property != NULL) {
772                 switch (property->type) {
773                 case DBUS_TYPE_STRING:
774                         *((char **) value) = property->value;
775                         found = TRUE;
776                         break;
777                 case DBUS_TYPE_BYTE:
778                         memcpy(value, property->value, 1);
779                         found = TRUE;
780                         break;
781                 }
782         }
783
784         __connman_element_unlock(element);
785
786         if (found == FALSE && element->parent != NULL)
787                 return get_static_property(element->parent, name, value);
788
789         return found;
790 }
791
792 static gboolean get_static_array_property(struct connman_element *element,
793                         const char *name, void *value, unsigned int *len)
794 {
795         struct connman_property *property;
796         gboolean found = FALSE;
797
798         DBG("element %p name %s", element, element->name);
799
800         __connman_element_lock(element);
801
802         property = g_hash_table_lookup(element->properties, name);
803         if (property != NULL) {
804                 *((char **) value) = property->value;
805                 *len = property->size;
806                 found = TRUE;
807         }
808
809         __connman_element_unlock(element);
810
811         return found;
812 }
813
814 #if 0
815 static gboolean match_static_property(struct connman_element *element,
816                                         const char *name, const void *value)
817 {
818         struct connman_property *property;
819         gboolean result = FALSE;
820
821         DBG("element %p name %s", element, element->name);
822
823         __connman_element_lock(element);
824
825         property = g_hash_table_lookup(element->properties, name);
826         if (property != NULL) {
827                 if (property->type == DBUS_TYPE_STRING)
828                         result = g_str_equal(property->value,
829                                                 *((const char **) value));
830         }
831
832         __connman_element_unlock(element);
833
834         return result;
835 }
836 #endif
837
838 /**
839  * connman_element_set_string:
840  * @element: element structure
841  * @key: unique identifier
842  * @value: string value
843  *
844  * Set string value for specific key
845  */
846 int connman_element_set_string(struct connman_element *element,
847                                         const char *key, const char *value)
848 {
849         return set_static_property(element, key, DBUS_TYPE_STRING, &value);
850 }
851
852 /**
853  * connman_element_get_string:
854  * @element: element structure
855  * @key: unique identifier
856  *
857  * Get string value for specific key
858  */
859 const char *connman_element_get_string(struct connman_element *element,
860                                                         const char *key)
861 {
862         const char *value;
863
864         if (get_static_property(element, key, &value) == FALSE)
865                 return NULL;
866
867         return value;
868 }
869
870 /**
871  * connman_element_set_uint8:
872  * @element: element structure
873  * @key: unique identifier
874  * @value: integer value
875  *
876  * Set integer value for specific key
877  */
878 int connman_element_set_uint8(struct connman_element *element,
879                                         const char *key, connman_uint8_t value)
880 {
881         return set_static_property(element, key, DBUS_TYPE_BYTE, &value);
882 }
883
884 /**
885  * connman_element_get_uint8:
886  * @element: element structure
887  * @key: unique identifier
888  *
889  * Get integer value for specific key
890  */
891 connman_uint8_t connman_element_get_uint8(struct connman_element *element,
892                                                         const char *key)
893 {
894         connman_uint8_t value;
895
896         if (get_static_property(element, key, &value) == FALSE)
897                 return 0;
898
899         return value;
900 }
901
902 /**
903  * connman_element_set_blob:
904  * @element: element structure
905  * @key: unique identifier
906  * @data: blob data
907  * @size: blob size
908  *
909  * Set binary blob value for specific key
910  */
911 int connman_element_set_blob(struct connman_element *element,
912                         const char *key, const void *data, unsigned int size)
913 {
914         return set_static_array_property(element, key,
915                                                 DBUS_TYPE_BYTE, &data, size);
916 }
917
918 /**
919  * connman_element_get_blob:
920  * @element: element structure
921  * @key: unique identifier
922  * @size: pointer to blob size
923  *
924  * Get binary blob value for specific key
925  */
926 const void *connman_element_get_blob(struct connman_element *element,
927                                         const char *key, unsigned int *size)
928 {
929         void *value;
930
931         if (get_static_array_property(element, key, &value, size) == FALSE)
932                 return NULL;
933
934         return value;
935 }
936
937 int __connman_element_append_ipv4(struct connman_element *element,
938                                                 DBusMessageIter *dict)
939 {
940         const char *method = NULL;
941         const char *address = NULL, *netmask = NULL, *gateway = NULL;
942         const char *broadcast = NULL, *nameserver = NULL;
943
944         connman_element_get_value(element,
945                                 CONNMAN_PROPERTY_ID_IPV4_METHOD, &method);
946
947         connman_element_get_value(element,
948                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
949         connman_element_get_value(element,
950                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
951         connman_element_get_value(element,
952                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
953         connman_element_get_value(element,
954                         CONNMAN_PROPERTY_ID_IPV4_BROADCAST, &broadcast);
955         connman_element_get_value(element,
956                         CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
957
958         if (method != NULL)
959                 connman_dbus_dict_append_variant(dict, "IPv4.Method",
960                                                 DBUS_TYPE_STRING, &method);
961
962         if (address != NULL)
963                 connman_dbus_dict_append_variant(dict, "IPv4.Address",
964                                                 DBUS_TYPE_STRING, &address);
965
966         if (netmask != NULL)
967                 connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
968                                                 DBUS_TYPE_STRING, &netmask);
969
970         if (gateway != NULL)
971                 connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
972                                                 DBUS_TYPE_STRING, &gateway);
973
974         if (broadcast != NULL)
975                 connman_dbus_dict_append_variant(dict, "IPv4.Broadcast",
976                                                 DBUS_TYPE_STRING, &broadcast);
977
978         if (nameserver != NULL)
979                 connman_dbus_dict_append_variant(dict, "IPv4.Nameserver",
980                                                 DBUS_TYPE_STRING, &nameserver);
981
982         return 0;
983 }
984
985 int __connman_element_set_ipv4(struct connman_element *element,
986                                 const char *name, DBusMessageIter *value)
987 {
988         int type;
989
990         type = dbus_message_iter_get_arg_type(value);
991
992         if (g_str_equal(name, "IPv4.Method") == TRUE) {
993                 enum connman_ipv4_method method;
994                 const char *str;
995
996                 if (type != DBUS_TYPE_STRING)
997                         return -EINVAL;
998
999                 dbus_message_iter_get_basic(value, &str);
1000                 method = __connman_ipv4_string2method(str);
1001                 if (method == CONNMAN_IPV4_METHOD_UNKNOWN)
1002                         return -EINVAL;
1003
1004                 if (method == element->ipv4.method)
1005                         return -EALREADY;
1006
1007                 element->ipv4.method = method;
1008
1009                 connman_element_update(element);
1010         } else if (g_str_equal(name, "IPv4.Address") == TRUE) {
1011                 const char *address;
1012
1013                 if (type != DBUS_TYPE_STRING)
1014                         return -EINVAL;
1015
1016                 dbus_message_iter_get_basic(value, &address);
1017
1018                 g_free(element->ipv4.address);
1019                 element->ipv4.address = g_strdup(address);
1020
1021                 connman_element_update(element);
1022         } else if (g_str_equal(name, "IPv4.Netmask") == TRUE) {
1023                 const char *netmask;
1024
1025                 if (type != DBUS_TYPE_STRING)
1026                         return -EINVAL;
1027
1028                 dbus_message_iter_get_basic(value, &netmask);
1029
1030                 g_free(element->ipv4.netmask);
1031                 element->ipv4.netmask = g_strdup(netmask);
1032
1033                 connman_element_update(element);
1034         } else if (g_str_equal(name, "IPv4.Gateway") == TRUE) {
1035                 const char *gateway;
1036
1037                 if (type != DBUS_TYPE_STRING)
1038                         return -EINVAL;
1039
1040                 dbus_message_iter_get_basic(value, &gateway);
1041
1042                 g_free(element->ipv4.gateway);
1043                 element->ipv4.gateway = g_strdup(gateway);
1044
1045                 connman_element_update(element);
1046         }
1047
1048         return 0;
1049 }
1050
1051 static void append_state(DBusMessageIter *entry, const char *state)
1052 {
1053         DBusMessageIter value;
1054         const char *key = "State";
1055
1056         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1057
1058         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1059                                         DBUS_TYPE_STRING_AS_STRING, &value);
1060         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1061         dbus_message_iter_close_container(entry, &value);
1062 }
1063
1064 static void emit_state_change(DBusConnection *conn, const char *state)
1065 {
1066         DBusMessage *signal;
1067         DBusMessageIter entry;
1068
1069         DBG("conn %p", conn);
1070
1071         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1072                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1073         if (signal == NULL)
1074                 return;
1075
1076         dbus_message_iter_init_append(signal, &entry);
1077
1078         append_state(&entry, state);
1079
1080         g_dbus_send_message(conn, signal);
1081
1082         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1083                                 CONNMAN_MANAGER_INTERFACE, "StateChanged");
1084         if (signal == NULL)
1085                 return;
1086
1087         dbus_message_iter_init_append(signal, &entry);
1088         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &state);
1089
1090         g_dbus_send_message(conn, signal);
1091 }
1092
1093 static void probe_element(struct connman_element *element)
1094 {
1095         GSList *list;
1096
1097         DBG("element %p name %s", element, element->name);
1098
1099         for (list = driver_list; list; list = list->next) {
1100                 struct connman_driver *driver = list->data;
1101
1102                 if (match_driver(element, driver) == FALSE)
1103                         continue;
1104
1105                 DBG("driver %p name %s", driver, driver->name);
1106
1107                 if (driver->probe(element) == 0) {
1108                         __connman_element_lock(element);
1109                         element->driver = driver;
1110                         __connman_element_unlock(element);
1111                         break;
1112                 }
1113         }
1114 }
1115
1116 static void register_element(gpointer data, gpointer user_data)
1117 {
1118         struct connman_element *element = data;
1119         const gchar *basepath;
1120         GNode *node;
1121
1122         __connman_element_lock(element);
1123
1124         if (element->parent) {
1125                 node = g_node_find(element_root, G_PRE_ORDER,
1126                                         G_TRAVERSE_ALL, element->parent);
1127                 basepath = element->parent->path;
1128         } else {
1129                 element->parent = element_root->data;
1130
1131                 node = element_root;
1132                 basepath = "/device";
1133         }
1134
1135         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1136
1137         __connman_element_unlock(element);
1138
1139         if (node == NULL) {
1140                 connman_error("Element registration for %s failed",
1141                                                         element->path);
1142                 return;
1143         }
1144
1145         DBG("element %p path %s", element, element->path);
1146
1147         g_node_append_data(node, element);
1148
1149         if (element->type == CONNMAN_ELEMENT_TYPE_DHCP) {
1150                 element->parent->configuring = TRUE;
1151
1152                 if (__connman_element_count(NULL,
1153                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1154                         emit_state_change(connection, "connecting");
1155         }
1156
1157         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1158                 struct connman_element *parent = element->parent;
1159
1160                 while (parent) {
1161                         parent->configuring = FALSE;
1162                         parent = parent->parent;
1163                 }
1164
1165                 if (__connman_element_count(NULL,
1166                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 1)
1167                         emit_state_change(connection, "online");
1168         }
1169
1170         emit_element_signal(connection, "ElementAdded", element);
1171
1172         if (started == FALSE)
1173                 return;
1174
1175         probe_element(element);
1176 }
1177
1178 /**
1179  * connman_element_register:
1180  * @element: the element to register
1181  * @parent: the parent to register the element with
1182  *
1183  * Register an element with the core. It will be register under the given
1184  * parent of if %NULL is provided under the root element.
1185  *
1186  * Returns: %0 on success
1187  */
1188 int connman_element_register(struct connman_element *element,
1189                                         struct connman_element *parent)
1190 {
1191         DBG("element %p name %s parent %p", element, element->name, parent);
1192
1193         if (element->devname == NULL)
1194                 element->devname = g_strdup(element->name);
1195
1196         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1197                 if (g_pattern_match_simple(device_filter,
1198                                                 element->devname) == FALSE) {
1199                         DBG("ignoring %s [%s] device", element->name,
1200                                                         element->devname);
1201                         return -EPERM;
1202                 }
1203         }
1204
1205         if (connman_element_ref(element) == NULL)
1206                 return -EINVAL;
1207
1208         __connman_element_lock(element);
1209
1210         if (element->name == NULL) {
1211                 element->name = g_strdup(type2string(element->type));
1212                 if (element->name == NULL) {
1213                         __connman_element_unlock(element);
1214                         return -EINVAL;
1215                 }
1216         }
1217
1218         if (element->type == CONNMAN_ELEMENT_TYPE_DHCP)
1219                 element->ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
1220
1221         element->parent = parent;
1222
1223         __connman_element_unlock(element);
1224
1225         register_element(element, NULL);
1226
1227         return 0;
1228 }
1229
1230 static gboolean remove_element(GNode *node, gpointer user_data)
1231 {
1232         struct connman_element *element = node->data;
1233         struct connman_element *root = user_data;
1234
1235         DBG("element %p name %s", element, element->name);
1236
1237         if (element == root)
1238                 return FALSE;
1239
1240         if (node != NULL)
1241                 g_node_unlink(node);
1242
1243         if (element->driver) {
1244                 if (element->driver->remove)
1245                         element->driver->remove(element);
1246
1247                 __connman_element_lock(element);
1248                 element->driver = NULL;
1249                 __connman_element_unlock(element);
1250         }
1251
1252         if (node != NULL)
1253                 g_node_destroy(node);
1254
1255         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1256                 if (__connman_element_count(NULL,
1257                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1258                         emit_state_change(connection, "offline");
1259         }
1260
1261         emit_element_signal(connection, "ElementRemoved", element);
1262
1263         connman_element_unref(element);
1264
1265         return FALSE;
1266 }
1267
1268 void connman_element_unregister(struct connman_element *element)
1269 {
1270         GNode *node;
1271
1272         DBG("element %p name %s", element, element->name);
1273
1274         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1275
1276         if (node != NULL)
1277                 g_node_traverse(node, G_POST_ORDER,
1278                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1279 }
1280
1281 void connman_element_unregister_children(struct connman_element *element)
1282 {
1283         GNode *node;
1284
1285         DBG("element %p name %s", element, element->name);
1286
1287         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1288
1289         if (node != NULL)
1290                 g_node_traverse(node, G_POST_ORDER,
1291                                 G_TRAVERSE_ALL, -1, remove_element, element);
1292 }
1293
1294 static gboolean update_element(GNode *node, gpointer user_data)
1295 {
1296         struct connman_element *element = node->data;
1297
1298         DBG("element %p name %s", element, element->name);
1299
1300         if (element->driver && element->driver->update)
1301                 element->driver->update(element);
1302
1303         emit_element_signal(connection, "ElementUpdated", element);
1304
1305         return FALSE;
1306 }
1307
1308 void connman_element_update(struct connman_element *element)
1309 {
1310         GNode *node;
1311
1312         DBG("element %p name %s", element, element->name);
1313
1314         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1315
1316         if (node != NULL)
1317                 g_node_traverse(node, G_PRE_ORDER,
1318                                 G_TRAVERSE_ALL, -1, update_element, element);
1319 }
1320
1321 int connman_element_set_enabled(struct connman_element *element,
1322                                                         gboolean enabled)
1323 {
1324         if (element->enabled == enabled)
1325                 return 0;
1326
1327         element->enabled = enabled;
1328
1329         connman_element_update(element);
1330
1331         return 0;
1332 }
1333
1334 /**
1335  * connman_element_set_error:
1336  * @element: element structure
1337  * @error: error identifier
1338  *
1339  * Set error state and specific error identifier
1340  */
1341 void connman_element_set_error(struct connman_element *element,
1342                                         enum connman_element_error error)
1343 {
1344         struct connman_service *service;
1345
1346         DBG("element %p error %d", element, error);
1347
1348         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1349                 return;
1350
1351         element->state = CONNMAN_ELEMENT_STATE_ERROR;
1352         element->error = error;
1353
1354         if (element->driver && element->driver->change)
1355                 element->driver->change(element);
1356
1357         service = __connman_element_get_service(element);
1358         __connman_service_indicate_state(service,
1359                                         CONNMAN_SERVICE_STATE_FAILURE);
1360 }
1361
1362 int __connman_element_init(DBusConnection *conn, const char *device,
1363                                                         const char *nodevice)
1364 {
1365         struct connman_element *element;
1366
1367         DBG("conn %p", conn);
1368
1369         connection = dbus_connection_ref(conn);
1370         if (connection == NULL)
1371                 return -EIO;
1372
1373         device_filter = g_strdup(device);
1374
1375         element = connman_element_create("root");
1376
1377         element->path = g_strdup("/");
1378         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1379
1380         element_root = g_node_new(element);
1381
1382         __connman_notifier_init();
1383         __connman_service_init();
1384         __connman_network_init();
1385         __connman_device_init();
1386
1387         return 0;
1388 }
1389
1390 static gboolean probe_node(GNode *node, gpointer data)
1391 {
1392         struct connman_element *element = node->data;
1393
1394         DBG("element %p name %s", element, element->name);
1395
1396         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1397                 return FALSE;
1398
1399         if (element->driver)
1400                 return FALSE;
1401
1402         probe_element(element);
1403
1404         return FALSE;
1405 }
1406
1407 void __connman_element_start(void)
1408 {
1409         DBG("");
1410
1411         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1412                                                         probe_node, NULL);
1413
1414         started = TRUE;
1415
1416         __connman_storage_init_device();
1417
1418         __connman_connection_init();
1419         __connman_ipv4_init();
1420         __connman_detect_init();
1421         __connman_rfkill_init();
1422 }
1423
1424 void __connman_element_stop(void)
1425 {
1426         DBG("");
1427
1428         __connman_rfkill_cleanup();
1429         __connman_detect_cleanup();
1430         __connman_ipv4_cleanup();
1431         __connman_connection_cleanup();
1432 }
1433
1434 static gboolean free_driver(GNode *node, gpointer data)
1435 {
1436         struct connman_element *element = node->data;
1437
1438         DBG("element %p name %s", element, element->name);
1439
1440         if (element->driver) {
1441                 if (element->driver->remove)
1442                         element->driver->remove(element);
1443
1444                 __connman_element_lock(element);
1445                 element->driver = NULL;
1446                 __connman_element_unlock(element);
1447         }
1448
1449         return FALSE;
1450 }
1451
1452 static gboolean free_node(GNode *node, gpointer data)
1453 {
1454         struct connman_element *element = node->data;
1455
1456         DBG("element %p name %s", element, element->name);
1457
1458         if (g_node_depth(node) > 1)
1459                 connman_element_unregister(element);
1460
1461         return FALSE;
1462 }
1463
1464 void __connman_element_cleanup(void)
1465 {
1466         DBG("");
1467
1468         __connman_device_cleanup();
1469         __connman_network_cleanup();
1470         __connman_service_cleanup();
1471         __connman_notifier_cleanup();
1472
1473         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1474                                                         free_driver, NULL);
1475
1476         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1477                                                         free_node, NULL);
1478
1479         g_node_destroy(element_root);
1480         element_root = NULL;
1481
1482         g_free(device_filter);
1483
1484         dbus_connection_unref(connection);
1485 }