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