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