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