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