6c07046f43b41340cf017db628f552f76ae71e32
[connman] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 static DBusConnection *connection;
36
37 static GNode *element_root = NULL;
38 static GSList *driver_list = NULL;
39 static gchar *device_filter = NULL;
40
41 static struct {
42         enum connman_property_id id;
43         int type;
44         const char *name;
45         const void *value;
46 } propid_table[] = {
47         { CONNMAN_PROPERTY_ID_IPV4_METHOD,
48                 DBUS_TYPE_STRING, "IPv4.Method", "dhcp" },
49         { CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
50                 DBUS_TYPE_STRING, "IPv4.Address" },
51         { CONNMAN_PROPERTY_ID_IPV4_NETMASK,
52                 DBUS_TYPE_STRING, "IPv4.Netmask" },
53         { CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
54                 DBUS_TYPE_STRING, "IPv4.Gateway" },
55         { CONNMAN_PROPERTY_ID_IPV4_BROADCAST,
56                 DBUS_TYPE_STRING, "IPv4.Broadcast" },
57         { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
58                 DBUS_TYPE_STRING, "IPv4.Nameserver" },
59
60         { CONNMAN_PROPERTY_ID_WIFI_SECURITY,
61                 DBUS_TYPE_STRING, "WiFi.Security" },
62         { CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE,
63                 DBUS_TYPE_STRING, "WiFi.Passphrase" },
64
65         { }
66 };
67
68 static int propid2type(enum connman_property_id id)
69 {
70         int i;
71
72         for (i = 0; propid_table[i].name; i++) {
73                 if (propid_table[i].id == id)
74                         return propid_table[i].type;
75         }
76
77         return DBUS_TYPE_INVALID;
78 }
79
80 static const char *propid2name(enum connman_property_id id)
81 {
82         int i;
83
84         for (i = 0; propid_table[i].name; i++) {
85                 if (propid_table[i].id == id)
86                         return propid_table[i].name;
87         }
88
89         return NULL;
90 }
91
92 static const char *type2string(enum connman_element_type type)
93 {
94         switch (type) {
95         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
96                 return "unknown";
97         case CONNMAN_ELEMENT_TYPE_ROOT:
98                 return "root";
99         case CONNMAN_ELEMENT_TYPE_PROFILE:
100                 return "profile";
101         case CONNMAN_ELEMENT_TYPE_DEVICE:
102                 return "device";
103         case CONNMAN_ELEMENT_TYPE_NETWORK:
104                 return "network";
105         case CONNMAN_ELEMENT_TYPE_SERVICE:
106                 return "service";
107         case CONNMAN_ELEMENT_TYPE_IPV4:
108                 return "ipv4";
109         case CONNMAN_ELEMENT_TYPE_IPV6:
110                 return "ipv6";
111         case CONNMAN_ELEMENT_TYPE_DHCP:
112                 return "dhcp";
113         case CONNMAN_ELEMENT_TYPE_BOOTP:
114                 return "bootp";
115         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
116                 return "zeroconf";
117         case CONNMAN_ELEMENT_TYPE_CONNECTION:
118                 return "connection";
119         }
120
121         return NULL;
122 }
123
124 static const char *subtype2string(enum connman_element_subtype type)
125 {
126         switch (type) {
127         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
128                 return "unknown";
129         case CONNMAN_ELEMENT_SUBTYPE_FAKE:
130                 return "fake";
131         case CONNMAN_ELEMENT_SUBTYPE_NETWORK:
132                 return "network";
133         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
134                 return "ethernet";
135         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
136                 return "wifi";
137         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
138                 return "wimax";
139         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
140                 return "modem";
141         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
142                 return "bluetooth";
143         }
144
145         return NULL;
146 }
147
148 static const char *subtype2description(enum connman_element_subtype type)
149 {
150         switch (type) {
151         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
152         case CONNMAN_ELEMENT_SUBTYPE_FAKE:
153         case CONNMAN_ELEMENT_SUBTYPE_NETWORK:
154                 return NULL;
155         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
156                 return "Ethernet";
157         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
158                 return "Wireless";
159         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
160                 return "WiMAX";
161         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
162                 return "Modem";
163         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
164                 return "Bluetooth";
165         }
166
167         return NULL;
168 }
169
170 const char *__connman_element_policy2string(enum connman_element_policy policy)
171 {
172         switch (policy) {
173         case CONNMAN_ELEMENT_POLICY_UNKNOWN:
174                 return "unknown";
175         case CONNMAN_ELEMENT_POLICY_IGNORE:
176                 return "ignore";
177         case CONNMAN_ELEMENT_POLICY_AUTO:
178                 return "auto";
179         case CONNMAN_ELEMENT_POLICY_ASK:
180                 return "ask";
181         }
182
183         return NULL;
184 }
185
186 enum connman_element_policy __connman_element_string2policy(const char *policy)
187 {
188         if (strcasecmp(policy, "ignore") == 0)
189                 return CONNMAN_ELEMENT_POLICY_IGNORE;
190         else if (strcasecmp(policy, "auto") == 0)
191                 return CONNMAN_ELEMENT_POLICY_AUTO;
192         else if (strcasecmp(policy, "ask") == 0)
193                 return CONNMAN_ELEMENT_POLICY_ASK;
194         else
195                 return CONNMAN_ELEMENT_POLICY_UNKNOWN;
196 }
197
198 const char *__connman_ipv4_method2string(enum connman_ipv4_method method)
199 {
200         switch (method) {
201         case CONNMAN_IPV4_METHOD_UNKNOWN:
202                 return "unknown";
203         case CONNMAN_IPV4_METHOD_OFF:
204                 return "off";
205         case CONNMAN_IPV4_METHOD_STATIC:
206                 return "static";
207         case CONNMAN_IPV4_METHOD_DHCP:
208                 return "dhcp";
209         }
210
211         return "unknown";
212 }
213
214 enum connman_ipv4_method __connman_ipv4_string2method(const char *method)
215 {
216         if (strcasecmp(method, "off") == 0)
217                 return CONNMAN_IPV4_METHOD_OFF;
218         else if (strcasecmp(method, "static") == 0)
219                 return CONNMAN_IPV4_METHOD_STATIC;
220         else if (strcasecmp(method, "dhcp") == 0)
221                 return CONNMAN_IPV4_METHOD_DHCP;
222         else
223                 return CONNMAN_IPV4_METHOD_UNKNOWN;
224 }
225
226 static void append_property(DBusMessageIter *dict,
227                                 struct connman_property *property)
228 {
229         if (property->value == NULL)
230                 return;
231
232         switch (property->type) {
233         case DBUS_TYPE_ARRAY:
234                 connman_dbus_dict_append_array(dict, property->name,
235                         property->subtype, &property->value, property->size);
236                 break;
237         case DBUS_TYPE_STRING:
238                 connman_dbus_dict_append_variant(dict, property->name,
239                                         property->type, &property->value);
240                 break;
241         default:
242                 connman_dbus_dict_append_variant(dict, property->name,
243                                         property->type, property->value);
244                 break;
245         }
246 }
247
248 static void add_common_properties(struct connman_element *element,
249                                                 DBusMessageIter *dict)
250 {
251         const char *address = NULL, *netmask = NULL, *gateway = NULL;
252         GSList *list;
253
254         connman_element_get_value(element,
255                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
256         connman_element_get_value(element,
257                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
258         connman_element_get_value(element,
259                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
260
261         if (element->priority > 0)
262                 connman_dbus_dict_append_variant(dict, "Priority",
263                                         DBUS_TYPE_UINT16, &element->priority);
264
265         if (address != NULL)
266                 connman_dbus_dict_append_variant(dict, "IPv4.Address",
267                                                 DBUS_TYPE_STRING, &address);
268         if (netmask != NULL)
269                 connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
270                                                 DBUS_TYPE_STRING, &netmask);
271         if (gateway != NULL)
272                 connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
273                                                 DBUS_TYPE_STRING, &gateway);
274
275         if (element->wifi.security != NULL) {
276                 const char *passphrase = "";
277
278                 connman_dbus_dict_append_variant(dict, "WiFi.Security",
279                                 DBUS_TYPE_STRING, &element->wifi.security);
280
281                 if (element->wifi.passphrase != NULL)
282                         passphrase = element->wifi.passphrase;
283
284                 connman_dbus_dict_append_variant(dict, "WiFi.Passphrase",
285                                 DBUS_TYPE_STRING, &passphrase);
286         }
287
288         __connman_element_lock(element);
289
290         for (list = element->properties; list; list = list->next) {
291                 struct connman_property *property = list->data;
292
293                 append_property(dict, property);
294         }
295
296         __connman_element_unlock(element);
297 }
298
299 static void set_common_property(struct connman_element *element,
300                                 const char *name, DBusMessageIter *value)
301 {
302         GSList *list;
303
304         if (g_str_equal(name, "Priority") == TRUE) {
305                 dbus_message_iter_get_basic(value, &element->priority);
306                 return;
307         }
308
309         __connman_element_lock(element);
310
311         for (list = element->properties; list; list = list->next) {
312                 struct connman_property *property = list->data;
313                 const char *str;
314
315                 if (g_str_equal(property->name, name) == FALSE)
316                         continue;
317
318                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
319                         continue;
320
321                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
322
323                 if (property->type == DBUS_TYPE_STRING) {
324                         dbus_message_iter_get_basic(value, &str);
325                         g_free(property->value);
326                         property->value = g_strdup(str);
327                 } else
328                         property->value = NULL;
329         }
330
331         __connman_element_unlock(element);
332 }
333
334 static void emit_enabled_signal(DBusConnection *conn,
335                                         struct connman_element *element)
336 {
337         DBusMessage *signal;
338         DBusMessageIter entry, value;
339         const char *iface, *key;
340
341         DBG("conn %p", conn);
342
343         if (element == NULL)
344                 return;
345
346         switch (element->type) {
347         case CONNMAN_ELEMENT_TYPE_DEVICE:
348                 iface = CONNMAN_DEVICE_INTERFACE;
349                 key = "Powered";
350                 break;
351         case CONNMAN_ELEMENT_TYPE_NETWORK:
352                 iface = CONNMAN_NETWORK_INTERFACE;
353                 key = "Connected";
354                 break;
355         case CONNMAN_ELEMENT_TYPE_CONNECTION:
356                 iface = CONNMAN_CONNECTION_INTERFACE;
357                 key = "Default";
358                 break;
359         default:
360                 return;
361         }
362
363         signal = dbus_message_new_signal(element->path,
364                                                 iface, "PropertyChanged");
365         if (signal == NULL)
366                 return;
367
368         dbus_message_iter_init_append(signal, &entry);
369
370         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
371
372         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
373                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
374         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
375                                                         &element->enabled);
376         dbus_message_iter_close_container(&entry, &value);
377
378         g_dbus_send_message(conn, signal);
379 }
380
381 static void emit_scanning_signal(DBusConnection *conn,
382                                         struct connman_element *element)
383 {
384         DBusMessage *signal;
385         DBusMessageIter entry, value;
386         const char *key = "Scanning";
387
388         DBG("conn %p", conn);
389
390         if (element == NULL)
391                 return;
392
393         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
394                 return;
395
396         signal = dbus_message_new_signal(element->path,
397                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
398         if (signal == NULL)
399                 return;
400
401         dbus_message_iter_init_append(signal, &entry);
402
403         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
404
405         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
406                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
407         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
408                                                         &element->scanning);
409         dbus_message_iter_close_container(&entry, &value);
410
411         g_dbus_send_message(conn, signal);
412 }
413
414 static DBusMessage *do_update(DBusConnection *conn,
415                                         DBusMessage *msg, void *data)
416 {
417         struct connman_element *element = data;
418
419         DBG("conn %p", conn);
420
421         if (element->enabled == FALSE)
422                 return __connman_error_failed(msg);
423
424         if (element->driver && element->driver->update) {
425                 DBG("Calling update callback");
426                 if (element->driver->update(element) < 0)
427                         return __connman_error_failed(msg);
428
429         }
430
431         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
432 }
433
434 static DBusMessage *do_enable(DBusConnection *conn,
435                                         DBusMessage *msg, void *data)
436 {
437         struct connman_element *element = data;
438
439         DBG("conn %p", conn);
440
441         if (element->enabled == TRUE)
442                 return __connman_error_failed(msg);
443
444         if (element->driver && element->driver->enable) {
445                 DBG("Calling enable callback");
446                 if (element->driver->enable(element) < 0)
447                         return __connman_error_failed(msg);
448         }
449
450         element->enabled = TRUE;
451
452         emit_enabled_signal(connection, element);
453
454         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
455 }
456
457 static DBusMessage *do_disable(DBusConnection *conn,
458                                         DBusMessage *msg, void *data)
459 {
460         struct connman_element *element = data;
461
462         DBG("conn %p", conn);
463
464         if (element->enabled == FALSE)
465                 return __connman_error_failed(msg);
466
467         if (element->driver && element->driver->disable) {
468                 DBG("Calling disable callback");
469                 if (element->driver->disable(element) < 0)
470                         return __connman_error_failed(msg);
471         }
472
473         element->enabled = FALSE;
474
475         emit_enabled_signal(connection, element);
476
477         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
478 }
479
480 static void append_networks(struct connman_element *element,
481                                                 DBusMessageIter *entry)
482 {
483         DBusMessageIter value, iter;
484         const char *key = "Networks";
485
486         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
487
488         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
489                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
490                                                                 &value);
491
492         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
493                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
494
495         __connman_element_list(element, CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
496
497         dbus_message_iter_close_container(&value, &iter);
498
499         dbus_message_iter_close_container(entry, &value);
500 }
501
502 static DBusMessage *device_get_properties(DBusConnection *conn,
503                                         DBusMessage *msg, void *data)
504 {
505         struct connman_element *element = data;
506         DBusMessage *reply;
507         DBusMessageIter array, dict, entry;
508         const char *str;
509
510         DBG("conn %p", conn);
511
512         reply = dbus_message_new_method_return(msg);
513         if (reply == NULL)
514                 return NULL;
515
516         dbus_message_iter_init_append(reply, &array);
517
518         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
519                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
520                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
521                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
522
523         str = subtype2description(element->subtype);
524         if (str != NULL && element->devname != NULL) {
525                 char *name = g_strdup_printf("%s (%s)", str, element->devname);
526                 if (name != NULL)
527                         connman_dbus_dict_append_variant(&dict, "Name",
528                                                 DBUS_TYPE_STRING, &name);
529                 g_free(name);
530         }
531
532         str = subtype2string(element->subtype);
533         if (str != NULL)
534                 connman_dbus_dict_append_variant(&dict, "Type",
535                                                 DBUS_TYPE_STRING, &str);
536
537         str = __connman_element_policy2string(element->policy);
538         if (str != NULL)
539                 connman_dbus_dict_append_variant(&dict, "Policy",
540                                                 DBUS_TYPE_STRING, &str);
541
542         connman_dbus_dict_append_variant(&dict, "Powered",
543                                         DBUS_TYPE_BOOLEAN, &element->enabled);
544
545         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIFI ||
546                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIMAX ||
547                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH) {
548                 connman_dbus_dict_append_variant(&dict, "Scanning",
549                                         DBUS_TYPE_BOOLEAN, &element->scanning);
550
551                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
552                                                                 NULL, &entry);
553                 append_networks(element, &entry);
554                 dbus_message_iter_close_container(&dict, &entry);
555         }
556
557         add_common_properties(element, &dict);
558
559         dbus_message_iter_close_container(&array, &dict);
560
561         return reply;
562 }
563
564 static DBusMessage *device_set_property(DBusConnection *conn,
565                                         DBusMessage *msg, void *data)
566 {
567         struct connman_element *element = data;
568         DBusMessageIter iter, value;
569         const char *name;
570
571         DBG("conn %p", conn);
572
573         if (dbus_message_iter_init(msg, &iter) == FALSE)
574                 return __connman_error_invalid_arguments(msg);
575
576         dbus_message_iter_get_basic(&iter, &name);
577         dbus_message_iter_next(&iter);
578         dbus_message_iter_recurse(&iter, &value);
579
580         if (__connman_security_check_privileges(msg) < 0)
581                 return __connman_error_permission_denied(msg);
582
583         if (g_str_equal(name, "Powered") == TRUE) {
584                 dbus_bool_t powered;
585
586                 dbus_message_iter_get_basic(&value, &powered);
587
588                 if (powered == TRUE)
589                         do_enable(conn, msg, element);
590                 else
591                         do_disable(conn, msg, element);
592         } else
593                 set_common_property(element, name, &value);
594
595         __connman_element_store(element);
596
597         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
598 }
599
600 static int parse_network_dict(DBusMessageIter *iter, const char **ssid,
601                                 const char **security, const char **passphrase)
602 {
603         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
604                 DBusMessageIter entry, value;
605                 const char *key;
606
607                 dbus_message_iter_recurse(iter, &entry);
608                 dbus_message_iter_get_basic(&entry, &key);
609
610                 dbus_message_iter_next(&entry);
611                 dbus_message_iter_recurse(&entry, &value);
612
613                 switch (dbus_message_iter_get_arg_type(&value)) {
614                 case DBUS_TYPE_STRING:
615                         if (g_str_equal(key, "WiFi.SSID") == TRUE)
616                                 dbus_message_iter_get_basic(&value, ssid);
617                         else if (g_str_equal(key, "WiFi.Security") == TRUE)
618                                 dbus_message_iter_get_basic(&value, security);
619                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
620                                 dbus_message_iter_get_basic(&value, passphrase);
621                         break;
622                 }
623
624                 dbus_message_iter_next(iter);
625         }
626
627         return 0;
628 }
629
630 static DBusMessage *device_create_network(DBusConnection *conn,
631                                         DBusMessage *msg, void *data)
632 {
633         struct connman_element *element = data;
634         struct connman_element *network;
635         DBusMessageIter iter, array;
636         const char *ssid = NULL, *security = NULL, *passphrase = NULL;
637
638         DBG("conn %p", conn);
639
640         if (dbus_message_iter_init(msg, &iter) == FALSE)
641                 return __connman_error_invalid_arguments(msg);
642
643         dbus_message_iter_recurse(&iter, &array);
644         parse_network_dict(&array, &ssid, &security, &passphrase);
645         if (ssid == NULL)
646                 return __connman_error_invalid_arguments(msg);
647
648         DBG("ssid %s security %s passphrase %s", ssid, security, passphrase);
649
650         network = connman_element_create(ssid);
651
652         network->type = CONNMAN_ELEMENT_TYPE_NETWORK;
653         network->index = element->index;
654
655         network->remember = TRUE;
656
657         connman_element_add_static_property(network, "Name",
658                                                 DBUS_TYPE_STRING, &ssid);
659
660         connman_element_add_static_array_property(element, "WiFi.SSID",
661                                         DBUS_TYPE_BYTE, &ssid, strlen(ssid));
662
663         network->wifi.security = g_strdup(security);
664         network->wifi.passphrase = g_strdup(passphrase);
665
666         connman_element_register(network, element);
667
668         return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &network->path,
669                                                         DBUS_TYPE_INVALID);
670 }
671
672 static DBusMessage *device_remove_network(DBusConnection *conn,
673                                         DBusMessage *msg, void *data)
674 {
675         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
676 }
677
678 static DBusMessage *network_get_properties(DBusConnection *conn,
679                                         DBusMessage *msg, void *data)
680 {
681         struct connman_element *element = data;
682         DBusMessage *reply;
683         DBusMessageIter array, dict;
684         const char *str;
685
686         DBG("conn %p", conn);
687
688         reply = dbus_message_new_method_return(msg);
689         if (reply == NULL)
690                 return NULL;
691
692         dbus_message_iter_init_append(reply, &array);
693
694         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
695                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
696                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
697                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
698
699         if (element->parent)
700                 connman_dbus_dict_append_variant(&dict, "Device",
701                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
702
703         str = __connman_element_policy2string(element->policy);
704         if (str != NULL)
705                 connman_dbus_dict_append_variant(&dict, "Policy",
706                                                 DBUS_TYPE_STRING, &str);
707
708         connman_dbus_dict_append_variant(&dict, "Available",
709                                         DBUS_TYPE_BOOLEAN, &element->available);
710
711         connman_dbus_dict_append_variant(&dict, "Connected",
712                                         DBUS_TYPE_BOOLEAN, &element->enabled);
713
714         connman_dbus_dict_append_variant(&dict, "Remember",
715                                         DBUS_TYPE_BOOLEAN, &element->remember);
716
717         add_common_properties(element, &dict);
718
719         dbus_message_iter_close_container(&array, &dict);
720
721         return reply;
722 }
723
724 static DBusMessage *network_set_property(DBusConnection *conn,
725                                         DBusMessage *msg, void *data)
726 {
727         struct connman_element *element = data;
728         DBusMessageIter iter;
729         DBusMessageIter value;
730         const char *name;
731
732         DBG("conn %p", conn);
733
734         if (dbus_message_iter_init(msg, &iter) == FALSE)
735                 return __connman_error_invalid_arguments(msg);
736
737         dbus_message_iter_get_basic(&iter, &name);
738         dbus_message_iter_next(&iter);
739         dbus_message_iter_recurse(&iter, &value);
740
741         if (__connman_security_check_privileges(msg) < 0)
742                 return __connman_error_permission_denied(msg);
743
744         if (g_str_equal(name, "Remember") == TRUE) {
745                 dbus_message_iter_get_basic(&value, &element->remember);
746         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
747                 const char *str;
748
749                 dbus_message_iter_get_basic(&value, &str);
750                 g_free(element->wifi.passphrase);
751                 element->wifi.passphrase = g_strdup(str);
752         } else
753                 set_common_property(element, name, &value);
754
755         __connman_element_store(element);
756
757         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
758 }
759
760 static DBusMessage *connection_get_properties(DBusConnection *conn,
761                                         DBusMessage *msg, void *data)
762 {
763         struct connman_element *element = data;
764         DBusMessage *reply;
765         DBusMessageIter array, dict;
766         const char *str;
767
768         DBG("conn %p", conn);
769
770         reply = dbus_message_new_method_return(msg);
771         if (reply == NULL)
772                 return NULL;
773
774         dbus_message_iter_init_append(reply, &array);
775
776         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
777                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
778                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
779                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
780
781         str = subtype2string(element->subtype);
782         if (str != NULL)
783                 connman_dbus_dict_append_variant(&dict, "Type",
784                                                 DBUS_TYPE_STRING, &str);
785
786         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIFI ||
787                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIMAX)
788                 connman_dbus_dict_append_variant(&dict, "Strength",
789                                         DBUS_TYPE_BYTE, &element->strength);
790
791         connman_dbus_dict_append_variant(&dict, "Default",
792                                         DBUS_TYPE_BOOLEAN, &element->enabled);
793
794         add_common_properties(element, &dict);
795
796         dbus_message_iter_close_container(&array, &dict);
797
798         return reply;
799 }
800
801 static DBusMessage *connection_set_property(DBusConnection *conn,
802                                         DBusMessage *msg, void *data)
803 {
804         struct connman_element *element = data;
805         DBusMessageIter iter, value;
806         const char *name;
807
808         DBG("conn %p", conn);
809
810         if (dbus_message_iter_init(msg, &iter) == FALSE)
811                 return __connman_error_invalid_arguments(msg);
812
813         dbus_message_iter_get_basic(&iter, &name);
814         dbus_message_iter_next(&iter);
815         dbus_message_iter_recurse(&iter, &value);
816
817         if (__connman_security_check_privileges(msg) < 0)
818                 return __connman_error_permission_denied(msg);
819
820         if (g_str_equal(name, "Default") == TRUE) {
821                 dbus_bool_t enabled;
822
823                 dbus_message_iter_get_basic(&value, &enabled);
824
825                 if (enabled == TRUE)
826                         return do_enable(conn, msg, element);
827                 else
828                         return do_disable(conn, msg, element);
829         }
830
831         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
832 }
833
834 static GDBusMethodTable device_methods[] = {
835         { "GetProperties", "",      "a{sv}", device_get_properties },
836         { "SetProperty",   "sv",    "",      device_set_property   },
837         { "CreateNetwork", "a{sv}", "o",     device_create_network },
838         { "RemoveNetwork", "o",     "",      device_remove_network },
839         { "ProposeScan",   "",      "",      do_update             },
840         { },
841 };
842
843 static GDBusMethodTable network_methods[] = {
844         { "GetProperties", "",   "a{sv}", network_get_properties },
845         { "SetProperty",   "sv", "",      network_set_property   },
846         { "Connect",       "",   "",      do_enable              },
847         { "Disconnect",    "",   "",      do_disable             },
848         { },
849 };
850
851 static GDBusMethodTable connection_methods[] = {
852         { "GetProperties", "",   "a{sv}", connection_get_properties },
853         { "SetProperty",   "sv", "",      connection_set_property   },
854         { },
855 };
856
857 static GDBusSignalTable element_signals[] = {
858         { "PropertyChanged", "sv" },
859         { },
860 };
861
862 struct append_filter {
863         enum connman_element_type type;
864         DBusMessageIter *iter;
865 };
866
867 static gboolean append_path(GNode *node, gpointer user_data)
868 {
869         struct connman_element *element = node->data;
870         struct append_filter *filter = user_data;
871
872         DBG("element %p name %s", element, element->name);
873
874         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
875                 return FALSE;
876
877         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
878                                         filter->type != element->type)
879                 return FALSE;
880
881         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
882                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
883                 return FALSE;
884
885         dbus_message_iter_append_basic(filter->iter,
886                                 DBUS_TYPE_OBJECT_PATH, &element->path);
887
888         return FALSE;
889 }
890
891 void __connman_element_list(struct connman_element *element,
892                                         enum connman_element_type type,
893                                                         DBusMessageIter *iter)
894 {
895         struct append_filter filter = { type, iter };
896         GNode *node;
897
898         DBG("");
899
900         if (element != NULL) {
901                 node = g_node_find(element_root, G_PRE_ORDER,
902                                                 G_TRAVERSE_ALL, element);
903                 if (node == NULL)
904                         return;
905         } else
906                 node = element_root;
907
908         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
909                                                 append_path, &filter);
910 }
911
912 struct count_data {
913         enum connman_element_type type;
914         int count;
915 };
916
917 static gboolean count_element(GNode *node, gpointer user_data)
918 {
919         struct connman_element *element = node->data;
920         struct count_data *data = user_data;
921
922         DBG("element %p name %s", element, element->name);
923
924         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
925                 return FALSE;
926
927         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
928                                         data->type != element->type)
929                 return FALSE;
930
931         data->count++;
932
933         return FALSE;
934 }
935
936 int __connman_element_count(struct connman_element *element,
937                                         enum connman_element_type type)
938 {
939         struct count_data data = { type, 0 };
940         GNode *node;
941
942         DBG("");
943
944         if (element != NULL) {
945                 node = g_node_find(element_root, G_PRE_ORDER,
946                                                 G_TRAVERSE_ALL, element);
947                 if (node == NULL)
948                         return 0;
949         } else
950                 node = element_root;
951
952         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
953                                                 count_element, &data);
954
955         return data.count;
956 }
957
958 static gint compare_priority(gconstpointer a, gconstpointer b)
959 {
960         const struct connman_driver *driver1 = a;
961         const struct connman_driver *driver2 = b;
962
963         return driver2->priority - driver1->priority;
964 }
965
966 static gboolean match_driver(struct connman_element *element,
967                                         struct connman_driver *driver)
968 {
969         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
970                 return FALSE;
971
972         if (element->type != driver->type &&
973                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
974                 return FALSE;
975
976         if (element->subtype == driver->subtype ||
977                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
978                 return TRUE;
979
980         return FALSE;
981 }
982
983 static void enable_element(struct connman_element *element)
984 {
985         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
986                 return;
987
988         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
989                 return;
990
991         if (element->driver && element->driver->enable) {
992                 if (element->driver->enable(element) == 0) {
993                         element->enabled = TRUE;
994                         emit_enabled_signal(connection, element);
995                 }
996         }
997 }
998
999 static gboolean probe_driver(GNode *node, gpointer data)
1000 {
1001         struct connman_element *element = node->data;
1002         struct connman_driver *driver = data;
1003
1004         DBG("element %p name %s", element, element->name);
1005
1006         if (!element->driver && match_driver(element, driver) == TRUE) {
1007                 if (driver->probe(element) < 0)
1008                         return FALSE;
1009
1010                 __connman_element_lock(element);
1011                 element->driver = driver;
1012                 __connman_element_unlock(element);
1013
1014                 enable_element(element);
1015         }
1016
1017         return FALSE;
1018 }
1019
1020 void __connman_driver_rescan(struct connman_driver *driver)
1021 {
1022         DBG("driver %p name %s", driver, driver->name);
1023
1024         if (!driver->probe)
1025                 return;
1026
1027         if (element_root != NULL)
1028                 g_node_traverse(element_root, G_PRE_ORDER,
1029                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
1030 }
1031
1032 /**
1033  * connman_driver_register:
1034  * @driver: driver definition
1035  *
1036  * Register a new driver
1037  *
1038  * Returns: %0 on success
1039  */
1040 int connman_driver_register(struct connman_driver *driver)
1041 {
1042         DBG("driver %p name %s", driver, driver->name);
1043
1044         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
1045                 return -EINVAL;
1046
1047         if (!driver->probe)
1048                 return -EINVAL;
1049
1050         driver_list = g_slist_insert_sorted(driver_list, driver,
1051                                                         compare_priority);
1052
1053         if (element_root != NULL)
1054                 g_node_traverse(element_root, G_PRE_ORDER,
1055                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
1056
1057         return 0;
1058 }
1059
1060 static void disable_element(struct connman_element *element)
1061 {
1062         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
1063                 return;
1064
1065         if (element->enabled == FALSE)
1066                 return;
1067
1068         if (element->driver && element->driver->disable) {
1069                 if (element->driver->disable(element) == 0) {
1070                         element->enabled = FALSE;
1071                         emit_enabled_signal(connection, element);
1072                 }
1073         }
1074 }
1075
1076 static gboolean remove_driver(GNode *node, gpointer data)
1077 {
1078         struct connman_element *element = node->data;
1079         struct connman_driver *driver = data;
1080
1081         DBG("element %p name %s", element, element->name);
1082
1083         if (element->driver == driver) {
1084                 disable_element(element);
1085
1086                 if (driver->remove)
1087                         driver->remove(element);
1088
1089                 __connman_element_lock(element);
1090                 element->driver = NULL;
1091                 __connman_element_unlock(element);
1092         }
1093
1094         return FALSE;
1095 }
1096
1097 /**
1098  * connman_driver_unregister:
1099  * @driver: driver definition
1100  *
1101  * Remove a previously registered driver
1102  */
1103 void connman_driver_unregister(struct connman_driver *driver)
1104 {
1105         DBG("driver %p name %s", driver, driver->name);
1106
1107         driver_list = g_slist_remove(driver_list, driver);
1108
1109         if (element_root != NULL)
1110                 g_node_traverse(element_root, G_POST_ORDER,
1111                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
1112 }
1113
1114 /**
1115  * connman_element_create:
1116  * @name: element name
1117  *
1118  * Allocate a new element and assign the given #name to it. If the name
1119  * is #NULL, it will be later on created based on the element type.
1120  *
1121  * Returns: a newly-allocated #connman_element structure
1122  */
1123 struct connman_element *connman_element_create(const char *name)
1124 {
1125         struct connman_element *element;
1126
1127         element = g_try_new0(struct connman_element, 1);
1128         if (element == NULL)
1129                 return NULL;
1130
1131         DBG("element %p", element);
1132
1133         element->refcount = 1;
1134
1135         element->name    = g_strdup(name);
1136         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
1137         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
1138         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
1139         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
1140         element->index   = -1;
1141         element->enabled = FALSE;
1142
1143         return element;
1144 }
1145
1146 struct connman_element *connman_element_ref(struct connman_element *element)
1147 {
1148         DBG("element %p name %s refcount %d", element, element->name,
1149                                 g_atomic_int_get(&element->refcount) + 1);
1150
1151         g_atomic_int_inc(&element->refcount);
1152
1153         return element;
1154 }
1155
1156 static void free_properties(struct connman_element *element)
1157 {
1158         GSList *list;
1159
1160         DBG("element %p name %s", element, element->name);
1161
1162         __connman_element_lock(element);
1163
1164         for (list = element->properties; list; list = list->next) {
1165                 struct connman_property *property = list->data;
1166
1167                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1168                         g_free(property->value);
1169
1170                 g_free(property->name);
1171                 g_free(property);
1172         }
1173
1174         g_slist_free(element->properties);
1175
1176         element->properties = NULL;
1177
1178         __connman_element_unlock(element);
1179 }
1180
1181 void connman_element_unref(struct connman_element *element)
1182 {
1183         DBG("element %p name %s refcount %d", element, element->name,
1184                                 g_atomic_int_get(&element->refcount) - 1);
1185
1186         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
1187                 free_properties(element);
1188                 g_free(element->ipv4.address);
1189                 g_free(element->ipv4.netmask);
1190                 g_free(element->ipv4.gateway);
1191                 g_free(element->ipv4.network);
1192                 g_free(element->ipv4.broadcast);
1193                 g_free(element->ipv4.nameserver);
1194                 g_free(element->devname);
1195                 g_free(element->path);
1196                 g_free(element->name);
1197                 g_free(element);
1198         }
1199 }
1200
1201 int connman_element_add_static_property(struct connman_element *element,
1202                                 const char *name, int type, const void *value)
1203 {
1204         struct connman_property *property;
1205
1206         DBG("element %p name %s", element, element->name);
1207
1208         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1209                 return -EINVAL;
1210
1211         property = g_try_new0(struct connman_property, 1);
1212         if (property == NULL)
1213                 return -ENOMEM;
1214
1215         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
1216         property->id    = CONNMAN_PROPERTY_ID_INVALID;
1217         property->name  = g_strdup(name);
1218         property->type  = type;
1219
1220         DBG("name %s type %d value %p", name, type, value);
1221
1222         switch (type) {
1223         case DBUS_TYPE_STRING:
1224                 property->value = g_strdup(*((const char **) value));
1225                 break;
1226         case DBUS_TYPE_BYTE:
1227                 property->value = g_try_malloc(1);
1228                 if (property->value != NULL)
1229                         memcpy(property->value, value, 1);
1230                 break;
1231         }
1232
1233         __connman_element_lock(element);
1234         element->properties = g_slist_append(element->properties, property);
1235         __connman_element_unlock(element);
1236
1237         return 0;
1238 }
1239
1240 static void emit_property_changed(DBusConnection *conn,
1241                                 struct connman_element *element,
1242                                 const char *name, int type, const void *data)
1243 {
1244         DBusMessage *signal;
1245         DBusMessageIter entry, value;
1246         const char *iface, *sig;
1247
1248         DBG("conn %p", conn);
1249
1250         switch (element->type) {
1251         case CONNMAN_ELEMENT_TYPE_DEVICE:
1252                 iface = CONNMAN_DEVICE_INTERFACE;
1253                 break;
1254         case CONNMAN_ELEMENT_TYPE_NETWORK:
1255                 iface = CONNMAN_NETWORK_INTERFACE;
1256                 break;
1257         case CONNMAN_ELEMENT_TYPE_CONNECTION:
1258                 iface = CONNMAN_CONNECTION_INTERFACE;
1259                 break;
1260         default:
1261                 return;
1262         }
1263
1264         signal = dbus_message_new_signal(element->path,
1265                                                 iface, "PropertyChanged");
1266         if (signal == NULL)
1267                 return;
1268
1269         dbus_message_iter_init_append(signal, &entry);
1270
1271         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1272
1273         switch (type) {
1274         case DBUS_TYPE_STRING:
1275                 sig = DBUS_TYPE_STRING_AS_STRING;
1276                 break;
1277         case DBUS_TYPE_BYTE:
1278                 sig = DBUS_TYPE_BYTE_AS_STRING;
1279                 break;
1280         default:
1281                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1282                 break;
1283         }
1284
1285         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1286                                                         sig, &value);
1287         dbus_message_iter_append_basic(&value, type, data);
1288         dbus_message_iter_close_container(&entry, &value);
1289
1290         g_dbus_send_message(conn, signal);
1291 }
1292
1293 int connman_element_set_static_property(struct connman_element *element,
1294                                 const char *name, int type, const void *value)
1295 {
1296         GSList *list;
1297
1298         DBG("element %p name %s", element, element->name);
1299
1300         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1301                 return -EINVAL;
1302
1303         __connman_element_lock(element);
1304
1305         for (list = element->properties; list; list = list->next) {
1306                 struct connman_property *property = list->data;
1307
1308                 if (g_str_equal(property->name, name) == FALSE)
1309                         continue;
1310
1311                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1312                         continue;
1313
1314                 property->type = type;
1315                 g_free(property->value);
1316
1317                 switch (type) {
1318                 case DBUS_TYPE_STRING:
1319                         property->value = g_strdup(*((const char **) value));
1320                         break;
1321                 case DBUS_TYPE_BYTE:
1322                         property->value = g_try_malloc(1);
1323                         if (property->value != NULL)
1324                                 memcpy(property->value, value, 1);
1325                         break;
1326                 }
1327         }
1328
1329         __connman_element_unlock(element);
1330
1331         emit_property_changed(connection, element, name, type, value);
1332
1333         return 0;
1334 }
1335
1336 int connman_element_add_static_array_property(struct connman_element *element,
1337                         const char *name, int type, const void *value, int len)
1338 {
1339         struct connman_property *property;
1340
1341         DBG("element %p name %s", element, element->name);
1342
1343         if (type != DBUS_TYPE_BYTE)
1344                 return -EINVAL;
1345
1346         property = g_try_new0(struct connman_property, 1);
1347         if (property == NULL)
1348                 return -ENOMEM;
1349
1350         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1351         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1352         property->name    = g_strdup(name);
1353         property->type    = DBUS_TYPE_ARRAY;
1354         property->subtype = type;
1355
1356         DBG("name %s type %d value %p", name, type, value);
1357
1358         switch (type) {
1359         case DBUS_TYPE_BYTE:
1360                 property->value = g_try_malloc(len);
1361                 if (property->value != NULL) {
1362                         memcpy(property->value,
1363                                 *((const unsigned char **) value), len);
1364                         property->size = len;
1365                 }
1366                 break;
1367         }
1368
1369         __connman_element_lock(element);
1370         element->properties = g_slist_append(element->properties, property);
1371         __connman_element_unlock(element);
1372
1373         return 0;
1374 }
1375
1376 static void *get_reference_value(struct connman_element *element,
1377                                                 enum connman_property_id id)
1378 {
1379         GSList *list;
1380
1381         DBG("element %p name %s", element, element->name);
1382
1383         for (list = element->properties; list; list = list->next) {
1384                 struct connman_property *property = list->data;
1385
1386                 if (property->id != id)
1387                         continue;
1388
1389                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1390                         return property->value;
1391         }
1392
1393         if (element->parent == NULL)
1394                 return NULL;
1395
1396         return get_reference_value(element->parent, id);
1397 }
1398
1399 static void set_reference_properties(struct connman_element *element)
1400 {
1401         GSList *list;
1402
1403         DBG("element %p name %s", element, element->name);
1404
1405         for (list = element->properties; list; list = list->next) {
1406                 struct connman_property *property = list->data;
1407
1408                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1409                         continue;
1410
1411                 property->value = get_reference_value(element->parent,
1412                                                                 property->id);
1413         }
1414 }
1415
1416 static struct connman_property *create_property(struct connman_element *element,
1417                                                 enum connman_property_id id)
1418 {
1419         struct connman_property *property;
1420         GSList *list;
1421
1422         DBG("element %p name %s", element, element->name);
1423
1424         __connman_element_lock(element);
1425
1426         for (list = element->properties; list; list = list->next) {
1427                 property = list->data;
1428
1429                 if (property->id == id)
1430                         goto unlock;
1431         }
1432
1433         property = g_try_new0(struct connman_property, 1);
1434         if (property == NULL)
1435                 goto unlock;
1436
1437         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1438         property->id    = id;
1439         property->name  = g_strdup(propid2name(id));
1440         property->type  = propid2type(id);
1441
1442         if (property->name == NULL) {
1443                 g_free(property);
1444                 property = NULL;
1445                 goto unlock;
1446         }
1447
1448         element->properties = g_slist_append(element->properties, property);
1449
1450 unlock:
1451         __connman_element_unlock(element);
1452
1453         return property;
1454 }
1455
1456 static void create_default_properties(struct connman_element *element)
1457 {
1458         struct connman_property *property;
1459         int i;
1460
1461         DBG("element %p name %s", element, element->name);
1462
1463         for (i = 0; propid_table[i].name; i++) {
1464                 DBG("property %s", propid_table[i].name);
1465
1466                 property = create_property(element, propid_table[i].id);
1467
1468                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1469
1470                 if (propid_table[i].type != DBUS_TYPE_STRING)
1471                         continue;
1472
1473                 if (propid_table[i].value)
1474                         property->value = g_strdup(propid_table[i].value);
1475                 else
1476                         property->value = g_strdup("");
1477         }
1478 }
1479
1480 static int define_properties_valist(struct connman_element *element,
1481                                                                 va_list args)
1482 {
1483         enum connman_property_id id;
1484
1485         DBG("element %p name %s", element, element->name);
1486
1487         id = va_arg(args, enum connman_property_id);
1488
1489         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1490
1491                 DBG("property %d", id);
1492
1493                 create_property(element, id);
1494
1495                 id = va_arg(args, enum connman_property_id);
1496         }
1497
1498         return 0;
1499 }
1500
1501 /**
1502  * connman_element_define_properties:
1503  * @element: an element
1504  * @varargs: list of property identifiers
1505  *
1506  * Define the valid properties for an element.
1507  *
1508  * Returns: %0 on success
1509  */
1510 int connman_element_define_properties(struct connman_element *element, ...)
1511 {
1512         va_list args;
1513         int err;
1514
1515         DBG("element %p name %s", element, element->name);
1516
1517         va_start(args, element);
1518
1519         err = define_properties_valist(element, args);
1520
1521         va_end(args);
1522
1523         return err;
1524 }
1525
1526 int connman_element_create_property(struct connman_element *element,
1527                                                 const char *name, int type)
1528 {
1529         return -EIO;
1530 }
1531
1532 int connman_element_set_property(struct connman_element *element,
1533                                 enum connman_property_id id, const void *value)
1534 {
1535         switch (id) {
1536         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1537                 __connman_element_lock(element);
1538                 g_free(element->ipv4.address);
1539                 element->ipv4.address = g_strdup(*((const char **) value));
1540                 __connman_element_unlock(element);
1541                 break;
1542         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1543                 __connman_element_lock(element);
1544                 g_free(element->ipv4.netmask);
1545                 element->ipv4.netmask = g_strdup(*((const char **) value));
1546                 __connman_element_unlock(element);
1547                 break;
1548         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1549                 __connman_element_lock(element);
1550                 g_free(element->ipv4.gateway);
1551                 element->ipv4.gateway = g_strdup(*((const char **) value));
1552                 __connman_element_unlock(element);
1553                 break;
1554         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1555                 __connman_element_lock(element);
1556                 g_free(element->ipv4.broadcast);
1557                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1558                 __connman_element_unlock(element);
1559                 break;
1560         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1561                 __connman_element_lock(element);
1562                 g_free(element->ipv4.nameserver);
1563                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1564                 __connman_element_unlock(element);
1565                 break;
1566         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1567                 __connman_element_lock(element);
1568                 g_free(element->wifi.security);
1569                 element->wifi.security = g_strdup(*((const char **) value));
1570                 __connman_element_unlock(element);
1571                 break;
1572         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1573                 __connman_element_lock(element);
1574                 g_free(element->wifi.passphrase);
1575                 element->wifi.passphrase = g_strdup(*((const char **) value));
1576                 __connman_element_unlock(element);
1577                 break;
1578         default:
1579                 return -EINVAL;
1580         }
1581
1582         return 0;
1583 }
1584
1585 int connman_element_get_value(struct connman_element *element,
1586                                 enum connman_property_id id, void *value)
1587 {
1588         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1589                 return -EINVAL;
1590
1591         switch (id) {
1592         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1593                 if (element->ipv4.address == NULL)
1594                         return connman_element_get_value(element->parent,
1595                                                                 id, value);
1596                 __connman_element_lock(element);
1597                 *((char **) value) = element->ipv4.address;
1598                 __connman_element_unlock(element);
1599                 break;
1600         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1601                 if (element->ipv4.netmask == NULL)
1602                         return connman_element_get_value(element->parent,
1603                                                                 id, value);
1604                 __connman_element_lock(element);
1605                 *((char **) value) = element->ipv4.netmask;
1606                 __connman_element_unlock(element);
1607                 break;
1608         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1609                 if (element->ipv4.gateway == NULL)
1610                         return connman_element_get_value(element->parent,
1611                                                                 id, value);
1612                 __connman_element_lock(element);
1613                 *((char **) value) = element->ipv4.gateway;
1614                 __connman_element_unlock(element);
1615                 break;
1616         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1617                 if (element->ipv4.broadcast == NULL)
1618                         return connman_element_get_value(element->parent,
1619                                                                 id, value);
1620                 __connman_element_lock(element);
1621                 *((char **) value) = element->ipv4.broadcast;
1622                 __connman_element_unlock(element);
1623                 break;
1624         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1625                 if (element->ipv4.nameserver == NULL)
1626                         return connman_element_get_value(element->parent,
1627                                                                 id, value);
1628                 __connman_element_lock(element);
1629                 *((char **) value) = element->ipv4.nameserver;
1630                 __connman_element_unlock(element);
1631                 break;
1632         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1633                 if (element->wifi.security == NULL)
1634                         return connman_element_get_value(element->parent,
1635                                                                 id, value);
1636                 __connman_element_lock(element);
1637                 *((char **) value) = element->wifi.security;
1638                 __connman_element_unlock(element);
1639                 break;
1640         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1641                 if (element->wifi.passphrase == NULL)
1642                         return connman_element_get_value(element->parent,
1643                                                                 id, value);
1644                 __connman_element_lock(element);
1645                 *((char **) value) = element->wifi.passphrase;
1646                 __connman_element_unlock(element);
1647                 break;
1648         default:
1649                 return -EINVAL;
1650         }
1651
1652         return 0;
1653 }
1654
1655 gboolean connman_element_get_static_property(struct connman_element *element,
1656                                                 const char *name, void *value)
1657 {
1658         GSList *list;
1659         gboolean found = FALSE;
1660
1661         DBG("element %p name %s", element, element->name);
1662
1663         __connman_element_lock(element);
1664
1665         for (list = element->properties; list; list = list->next) {
1666                 struct connman_property *property = list->data;
1667
1668                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1669                         continue;
1670
1671                 if (g_str_equal(property->name, name) == TRUE) {
1672                         switch (property->type) {
1673                         case DBUS_TYPE_STRING:
1674                                 *((char **) value) = property->value;
1675                                 found = TRUE;
1676                                 break;
1677                         }
1678                         break;
1679                 }
1680         }
1681
1682         __connman_element_unlock(element);
1683
1684         return found;
1685 }
1686
1687 gboolean connman_element_get_static_array_property(struct connman_element *element,
1688                                         const char *name, void *value, int *len)
1689 {
1690         GSList *list;
1691         gboolean found = FALSE;
1692
1693         DBG("element %p name %s", element, element->name);
1694
1695         __connman_element_lock(element);
1696
1697         for (list = element->properties; list; list = list->next) {
1698                 struct connman_property *property = list->data;
1699
1700                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1701                         continue;
1702
1703                 if (g_str_equal(property->name, name) == TRUE) {
1704                         *((char **) value) = property->value;
1705                         *len = property->size;
1706                         found = TRUE;
1707                         break;
1708                 }
1709         }
1710
1711         __connman_element_unlock(element);
1712
1713         return found;
1714 }
1715
1716 gboolean connman_element_match_static_property(struct connman_element *element,
1717                                         const char *name, const void *value)
1718 {
1719         GSList *list;
1720         gboolean result = FALSE;
1721
1722         DBG("element %p name %s", element, element->name);
1723
1724         __connman_element_lock(element);
1725
1726         for (list = element->properties; list; list = list->next) {
1727                 struct connman_property *property = list->data;
1728
1729                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1730                         continue;
1731
1732                 if (g_str_equal(property->name, name) == FALSE)
1733                         continue;
1734
1735                 if (property->type == DBUS_TYPE_STRING)
1736                         result = g_str_equal(property->value,
1737                                                 *((const char **) value));
1738
1739                 if (result == TRUE)
1740                         break;
1741         }
1742
1743         __connman_element_unlock(element);
1744
1745         return result;
1746 }
1747
1748 static void append_devices(DBusMessageIter *entry)
1749 {
1750         DBusMessageIter value, iter;
1751         const char *key = "Devices";
1752
1753         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1754
1755         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1756                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1757                                                                 &value);
1758
1759         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1760                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1761         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1762         dbus_message_iter_close_container(&value, &iter);
1763
1764         dbus_message_iter_close_container(entry, &value);
1765 }
1766
1767 static void emit_devices_signal(DBusConnection *conn)
1768 {
1769         DBusMessage *signal;
1770         DBusMessageIter entry;
1771
1772         DBG("conn %p", conn);
1773
1774         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1775                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1776         if (signal == NULL)
1777                 return;
1778
1779         dbus_message_iter_init_append(signal, &entry);
1780
1781         append_devices(&entry);
1782
1783         g_dbus_send_message(conn, signal);
1784 }
1785
1786 static void emit_networks_signal(DBusConnection *conn,
1787                                         struct connman_element *device)
1788 {
1789         DBusMessage *signal;
1790         DBusMessageIter entry;
1791
1792         DBG("conn %p", conn);
1793
1794         if (device == NULL)
1795                 return;
1796
1797         signal = dbus_message_new_signal(device->path,
1798                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1799         if (signal == NULL)
1800                 return;
1801
1802         dbus_message_iter_init_append(signal, &entry);
1803
1804         append_networks(device, &entry);
1805
1806         g_dbus_send_message(conn, signal);
1807 }
1808
1809 static void append_connections(DBusMessageIter *entry)
1810 {
1811         DBusMessageIter value, iter;
1812         const char *key = "Connections";
1813
1814         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1815
1816         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1817                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1818                                                                 &value);
1819
1820         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1821                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1822         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1823         dbus_message_iter_close_container(&value, &iter);
1824
1825         dbus_message_iter_close_container(entry, &value);
1826 }
1827
1828 static void emit_connections_signal(DBusConnection *conn)
1829 {
1830         DBusMessage *signal;
1831         DBusMessageIter entry;
1832
1833         DBG("conn %p", conn);
1834
1835         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1836                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1837         if (signal == NULL)
1838                 return;
1839
1840         dbus_message_iter_init_append(signal, &entry);
1841
1842         append_connections(&entry);
1843
1844         g_dbus_send_message(conn, signal);
1845 }
1846
1847 static void append_state(DBusMessageIter *entry, const char *state)
1848 {
1849         DBusMessageIter value;
1850         const char *key = "State";
1851
1852         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1853
1854         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1855                                         DBUS_TYPE_STRING_AS_STRING, &value);
1856         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1857         dbus_message_iter_close_container(entry, &value);
1858 }
1859
1860 static void emit_state_change(DBusConnection *conn, const char *state)
1861 {
1862         DBusMessage *signal;
1863         DBusMessageIter entry;
1864
1865         DBG("conn %p", conn);
1866
1867         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1868                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1869         if (signal == NULL)
1870                 return;
1871
1872         dbus_message_iter_init_append(signal, &entry);
1873
1874         append_state(&entry, state);
1875
1876         g_dbus_send_message(conn, signal);
1877 }
1878
1879 static void set_signal_strength(struct connman_element *connection)
1880 {
1881         struct connman_element *element = connection;
1882
1883         while (element != NULL) {
1884                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1885                         connection->strength = element->strength;
1886                         break;
1887                 }
1888
1889                 element = element->parent;
1890         }
1891 }
1892
1893 static void register_element(gpointer data, gpointer user_data)
1894 {
1895         struct connman_element *element = data;
1896         const gchar *basepath;
1897         GSList *list;
1898         GNode *node;
1899
1900         __connman_element_lock(element);
1901
1902         if (element->parent) {
1903                 node = g_node_find(element_root, G_PRE_ORDER,
1904                                         G_TRAVERSE_ALL, element->parent);
1905                 basepath = element->parent->path;
1906
1907                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1908                         element->subtype = element->parent->subtype;
1909         } else {
1910                 element->parent = element_root->data;
1911
1912                 node = element_root;
1913                 basepath = "";
1914         }
1915
1916         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1917
1918         set_reference_properties(element);
1919
1920         __connman_element_unlock(element);
1921
1922         DBG("element %p path %s", element, element->path);
1923
1924         __connman_element_load(element);
1925
1926         g_node_append_data(node, element);
1927
1928         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1929                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1930                 if (g_dbus_register_interface(connection, element->path,
1931                                         CONNMAN_DEVICE_INTERFACE,
1932                                         device_methods, element_signals,
1933                                         NULL, element, NULL) == FALSE)
1934                         connman_error("Failed to register %s device",
1935                                                                 element->path);
1936                 else
1937                         emit_devices_signal(connection);
1938         }
1939
1940         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1941                 if (g_dbus_register_interface(connection, element->path,
1942                                         CONNMAN_NETWORK_INTERFACE,
1943                                         network_methods, element_signals,
1944                                         NULL, element, NULL) == FALSE)
1945                         connman_error("Failed to register %s network",
1946                                                                 element->path);
1947                 else
1948                         emit_networks_signal(connection, element->parent);
1949         }
1950
1951         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1952                 if (g_dbus_register_interface(connection, element->path,
1953                                         CONNMAN_CONNECTION_INTERFACE,
1954                                         connection_methods, element_signals,
1955                                         NULL, element, NULL) == FALSE)
1956                         connman_error("Failed to register %s connection",
1957                                                                 element->path);
1958                 else {
1959                         set_signal_strength(element);
1960                         emit_connections_signal(connection);
1961                         emit_state_change(connection, "online");
1962                 }
1963         }
1964
1965         __connman_element_store(element);
1966
1967         for (list = driver_list; list; list = list->next) {
1968                 struct connman_driver *driver = list->data;
1969
1970                 if (match_driver(element, driver) == FALSE)
1971                         continue;
1972
1973                 DBG("driver %p name %s", driver, driver->name);
1974
1975                 if (driver->probe(element) == 0) {
1976                         __connman_element_lock(element);
1977                         element->driver = driver;
1978                         __connman_element_unlock(element);
1979
1980                         enable_element(element);
1981                         break;
1982                 }
1983         }
1984 }
1985
1986 /**
1987  * connman_element_register:
1988  * @element: the element to register
1989  * @parent: the parent to register the element with
1990  *
1991  * Register an element with the core. It will be register under the given
1992  * parent of if %NULL is provided under the root element.
1993  *
1994  * Returns: %0 on success
1995  */
1996 int connman_element_register(struct connman_element *element,
1997                                         struct connman_element *parent)
1998 {
1999         DBG("element %p name %s parent %p", element, element->name, parent);
2000
2001         if (element->devname == NULL)
2002                 element->devname = g_strdup(element->name);
2003
2004         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2005                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2006                 if (g_pattern_match_simple(device_filter,
2007                                                 element->devname) == FALSE) {
2008                         DBG("ignoring %s [%s] device", element->name,
2009                                                         element->devname);
2010                         return -EPERM;
2011                 }
2012         }
2013
2014         if (connman_element_ref(element) == NULL)
2015                 return -EINVAL;
2016
2017         __connman_element_lock(element);
2018
2019         if (element->name == NULL) {
2020                 element->name = g_strdup(type2string(element->type));
2021                 if (element->name == NULL) {
2022                         __connman_element_unlock(element);
2023                         return -EINVAL;
2024                 }
2025         }
2026
2027         element->parent = parent;
2028
2029         __connman_element_unlock(element);
2030
2031         register_element(element, NULL);
2032
2033         return 0;
2034 }
2035
2036 static gboolean remove_element(GNode *node, gpointer user_data)
2037 {
2038         struct connman_element *element = node->data;
2039         struct connman_element *root = user_data;
2040
2041         DBG("element %p name %s", element, element->name);
2042
2043         if (element == root)
2044                 return FALSE;
2045
2046         if (element->driver) {
2047                 disable_element(element);
2048
2049                 if (element->driver->remove)
2050                         element->driver->remove(element);
2051
2052                 __connman_element_lock(element);
2053                 element->driver = NULL;
2054                 __connman_element_unlock(element);
2055         }
2056
2057         if (node != NULL) {
2058                 g_node_unlink(node);
2059                 g_node_destroy(node);
2060         }
2061
2062         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
2063                 if (__connman_element_count(NULL,
2064                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
2065                         emit_state_change(connection, "offline");
2066                 emit_connections_signal(connection);
2067
2068                 g_dbus_unregister_interface(connection, element->path,
2069                                                 CONNMAN_CONNECTION_INTERFACE);
2070         }
2071
2072         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2073                 emit_networks_signal(connection, element->parent);
2074
2075                 g_dbus_unregister_interface(connection, element->path,
2076                                                 CONNMAN_NETWORK_INTERFACE);
2077         }
2078
2079         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2080                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2081                 emit_devices_signal(connection);
2082
2083                 g_dbus_unregister_interface(connection, element->path,
2084                                                 CONNMAN_DEVICE_INTERFACE);
2085         }
2086
2087         connman_element_unref(element);
2088
2089         return FALSE;
2090 }
2091
2092 void connman_element_unregister(struct connman_element *element)
2093 {
2094         GNode *node;
2095
2096         DBG("element %p name %s", element, element->name);
2097
2098         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2099
2100         if (node != NULL)
2101                 g_node_traverse(node, G_POST_ORDER,
2102                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
2103 }
2104
2105 void connman_element_unregister_children(struct connman_element *element)
2106 {
2107         GNode *node;
2108
2109         DBG("element %p name %s", element, element->name);
2110
2111         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2112
2113         if (node != NULL)
2114                 g_node_traverse(node, G_POST_ORDER,
2115                                 G_TRAVERSE_ALL, -1, remove_element, element);
2116 }
2117
2118 static gboolean update_element(GNode *node, gpointer user_data)
2119 {
2120         struct connman_element *element = node->data;
2121         struct connman_element *root = user_data;
2122
2123         DBG("element %p name %s", element, element->name);
2124
2125         if (element->driver && element->driver->update)
2126                 element->driver->update(element);
2127
2128         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION &&
2129                                 root->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2130                 if (element->strength != root->strength) {
2131                         element->strength = root->strength;
2132                         emit_property_changed(connection, element, "Strength",
2133                                         DBUS_TYPE_BYTE, &element->strength);
2134                 }
2135         }
2136
2137         return FALSE;
2138 }
2139
2140 void connman_element_update(struct connman_element *element)
2141 {
2142         GNode *node;
2143
2144         DBG("element %p name %s", element, element->name);
2145
2146         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2147
2148         if (node != NULL)
2149                 g_node_traverse(node, G_PRE_ORDER,
2150                                 G_TRAVERSE_ALL, -1, update_element, element);
2151 }
2152
2153 int connman_element_set_enabled(struct connman_element *element,
2154                                                         gboolean enabled)
2155 {
2156         if (element->enabled == enabled)
2157                 return 0;
2158
2159         element->enabled = enabled;
2160
2161         emit_enabled_signal(connection, element);
2162
2163         return 0;
2164 }
2165
2166 int connman_element_set_scanning(struct connman_element *element,
2167                                                         gboolean scanning)
2168 {
2169         if (element->scanning == scanning)
2170                 return 0;
2171
2172         element->scanning = scanning;
2173
2174         emit_scanning_signal(connection, element);
2175
2176         return 0;
2177 }
2178
2179 int __connman_element_init(DBusConnection *conn, const char *device)
2180 {
2181         struct connman_element *element;
2182
2183         DBG("conn %p", conn);
2184
2185         connection = dbus_connection_ref(conn);
2186         if (connection == NULL)
2187                 return -EIO;
2188
2189         device_filter = g_strdup(device);
2190
2191         element = connman_element_create("root");
2192
2193         element->path = g_strdup("/");
2194         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
2195
2196         create_default_properties(element);
2197
2198         element_root = g_node_new(element);
2199
2200         __connman_device_init();
2201
2202         return 0;
2203 }
2204
2205 static gboolean free_driver(GNode *node, gpointer data)
2206 {
2207         struct connman_element *element = node->data;
2208
2209         DBG("element %p name %s", element, element->name);
2210
2211         if (element->driver) {
2212                 disable_element(element);
2213
2214                 if (element->driver->remove)
2215                         element->driver->remove(element);
2216
2217                 __connman_element_lock(element);
2218                 element->driver = NULL;
2219                 __connman_element_unlock(element);
2220         }
2221
2222         return FALSE;
2223 }
2224
2225 static gboolean free_node(GNode *node, gpointer data)
2226 {
2227         struct connman_element *element = node->data;
2228
2229         DBG("element %p name %s", element, element->name);
2230
2231         if (g_node_depth(node) > 1)
2232                 connman_element_unregister(element);
2233
2234         return FALSE;
2235 }
2236
2237 void __connman_element_cleanup(void)
2238 {
2239         DBG("");
2240
2241         __connman_device_cleanup();
2242
2243         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2244                                                         free_driver, NULL);
2245
2246         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2247                                                         free_node, NULL);
2248
2249         g_node_destroy(element_root);
2250         element_root = NULL;
2251
2252         g_free(device_filter);
2253
2254         dbus_connection_unref(connection);
2255 }