Only allow WiFi devices to create networks for now
[platform/upstream/connman.git] / 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 (element->subtype != CONNMAN_ELEMENT_SUBTYPE_WIFI)
641                 return __connman_error_invalid_arguments(msg);
642
643         if (dbus_message_iter_init(msg, &iter) == FALSE)
644                 return __connman_error_invalid_arguments(msg);
645
646         dbus_message_iter_recurse(&iter, &array);
647         parse_network_dict(&array, &ssid, &security, &passphrase);
648         if (ssid == NULL)
649                 return __connman_error_invalid_arguments(msg);
650
651         DBG("ssid %s security %s passphrase %s", ssid, security, passphrase);
652
653         network = connman_element_create(ssid);
654
655         network->type = CONNMAN_ELEMENT_TYPE_NETWORK;
656         network->index = element->index;
657
658         network->remember = TRUE;
659
660         connman_element_add_static_property(network, "Name",
661                                                 DBUS_TYPE_STRING, &ssid);
662
663         connman_element_add_static_array_property(element, "WiFi.SSID",
664                                         DBUS_TYPE_BYTE, &ssid, strlen(ssid));
665
666         network->wifi.security = g_strdup(security);
667         network->wifi.passphrase = g_strdup(passphrase);
668
669         connman_element_register(network, element);
670
671         return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &network->path,
672                                                         DBUS_TYPE_INVALID);
673 }
674
675 static DBusMessage *device_remove_network(DBusConnection *conn,
676                                         DBusMessage *msg, void *data)
677 {
678         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
679 }
680
681 static DBusMessage *network_get_properties(DBusConnection *conn,
682                                         DBusMessage *msg, void *data)
683 {
684         struct connman_element *element = data;
685         DBusMessage *reply;
686         DBusMessageIter array, dict;
687         const char *str;
688
689         DBG("conn %p", conn);
690
691         reply = dbus_message_new_method_return(msg);
692         if (reply == NULL)
693                 return NULL;
694
695         dbus_message_iter_init_append(reply, &array);
696
697         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
698                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
699                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
700                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
701
702         if (element->parent)
703                 connman_dbus_dict_append_variant(&dict, "Device",
704                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
705
706         str = __connman_element_policy2string(element->policy);
707         if (str != NULL)
708                 connman_dbus_dict_append_variant(&dict, "Policy",
709                                                 DBUS_TYPE_STRING, &str);
710
711         connman_dbus_dict_append_variant(&dict, "Available",
712                                         DBUS_TYPE_BOOLEAN, &element->available);
713
714         connman_dbus_dict_append_variant(&dict, "Connected",
715                                         DBUS_TYPE_BOOLEAN, &element->enabled);
716
717         connman_dbus_dict_append_variant(&dict, "Remember",
718                                         DBUS_TYPE_BOOLEAN, &element->remember);
719
720         add_common_properties(element, &dict);
721
722         dbus_message_iter_close_container(&array, &dict);
723
724         return reply;
725 }
726
727 static DBusMessage *network_set_property(DBusConnection *conn,
728                                         DBusMessage *msg, void *data)
729 {
730         struct connman_element *element = data;
731         DBusMessageIter iter;
732         DBusMessageIter value;
733         const char *name;
734
735         DBG("conn %p", conn);
736
737         if (dbus_message_iter_init(msg, &iter) == FALSE)
738                 return __connman_error_invalid_arguments(msg);
739
740         dbus_message_iter_get_basic(&iter, &name);
741         dbus_message_iter_next(&iter);
742         dbus_message_iter_recurse(&iter, &value);
743
744         if (__connman_security_check_privileges(msg) < 0)
745                 return __connman_error_permission_denied(msg);
746
747         if (g_str_equal(name, "Remember") == TRUE) {
748                 dbus_message_iter_get_basic(&value, &element->remember);
749         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
750                 const char *str;
751
752                 dbus_message_iter_get_basic(&value, &str);
753                 g_free(element->wifi.passphrase);
754                 element->wifi.passphrase = g_strdup(str);
755         } else
756                 set_common_property(element, name, &value);
757
758         __connman_element_store(element);
759
760         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
761 }
762
763 static DBusMessage *connection_get_properties(DBusConnection *conn,
764                                         DBusMessage *msg, void *data)
765 {
766         struct connman_element *element = data;
767         DBusMessage *reply;
768         DBusMessageIter array, dict;
769         const char *str;
770
771         DBG("conn %p", conn);
772
773         reply = dbus_message_new_method_return(msg);
774         if (reply == NULL)
775                 return NULL;
776
777         dbus_message_iter_init_append(reply, &array);
778
779         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
780                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
781                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
782                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
783
784         str = subtype2string(element->subtype);
785         if (str != NULL)
786                 connman_dbus_dict_append_variant(&dict, "Type",
787                                                 DBUS_TYPE_STRING, &str);
788
789         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIFI ||
790                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIMAX)
791                 connman_dbus_dict_append_variant(&dict, "Strength",
792                                         DBUS_TYPE_BYTE, &element->strength);
793
794         connman_dbus_dict_append_variant(&dict, "Default",
795                                         DBUS_TYPE_BOOLEAN, &element->enabled);
796
797         add_common_properties(element, &dict);
798
799         dbus_message_iter_close_container(&array, &dict);
800
801         return reply;
802 }
803
804 static DBusMessage *connection_set_property(DBusConnection *conn,
805                                         DBusMessage *msg, void *data)
806 {
807         struct connman_element *element = data;
808         DBusMessageIter iter, value;
809         const char *name;
810
811         DBG("conn %p", conn);
812
813         if (dbus_message_iter_init(msg, &iter) == FALSE)
814                 return __connman_error_invalid_arguments(msg);
815
816         dbus_message_iter_get_basic(&iter, &name);
817         dbus_message_iter_next(&iter);
818         dbus_message_iter_recurse(&iter, &value);
819
820         if (__connman_security_check_privileges(msg) < 0)
821                 return __connman_error_permission_denied(msg);
822
823         if (g_str_equal(name, "Default") == TRUE) {
824                 dbus_bool_t enabled;
825
826                 dbus_message_iter_get_basic(&value, &enabled);
827
828                 if (enabled == TRUE)
829                         return do_enable(conn, msg, element);
830                 else
831                         return do_disable(conn, msg, element);
832         }
833
834         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
835 }
836
837 static GDBusMethodTable device_methods[] = {
838         { "GetProperties", "",      "a{sv}", device_get_properties },
839         { "SetProperty",   "sv",    "",      device_set_property   },
840         { "CreateNetwork", "a{sv}", "o",     device_create_network },
841         { "RemoveNetwork", "o",     "",      device_remove_network },
842         { "ProposeScan",   "",      "",      do_update             },
843         { },
844 };
845
846 static GDBusMethodTable network_methods[] = {
847         { "GetProperties", "",   "a{sv}", network_get_properties },
848         { "SetProperty",   "sv", "",      network_set_property   },
849         { "Connect",       "",   "",      do_enable              },
850         { "Disconnect",    "",   "",      do_disable             },
851         { },
852 };
853
854 static GDBusMethodTable connection_methods[] = {
855         { "GetProperties", "",   "a{sv}", connection_get_properties },
856         { "SetProperty",   "sv", "",      connection_set_property   },
857         { },
858 };
859
860 static GDBusSignalTable element_signals[] = {
861         { "PropertyChanged", "sv" },
862         { },
863 };
864
865 struct append_filter {
866         enum connman_element_type type;
867         DBusMessageIter *iter;
868 };
869
870 static gboolean append_path(GNode *node, gpointer user_data)
871 {
872         struct connman_element *element = node->data;
873         struct append_filter *filter = user_data;
874
875         DBG("element %p name %s", element, element->name);
876
877         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
878                 return FALSE;
879
880         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
881                                         filter->type != element->type)
882                 return FALSE;
883
884         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
885                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
886                 return FALSE;
887
888         dbus_message_iter_append_basic(filter->iter,
889                                 DBUS_TYPE_OBJECT_PATH, &element->path);
890
891         return FALSE;
892 }
893
894 void __connman_element_list(struct connman_element *element,
895                                         enum connman_element_type type,
896                                                         DBusMessageIter *iter)
897 {
898         struct append_filter filter = { type, iter };
899         GNode *node;
900
901         DBG("");
902
903         if (element != NULL) {
904                 node = g_node_find(element_root, G_PRE_ORDER,
905                                                 G_TRAVERSE_ALL, element);
906                 if (node == NULL)
907                         return;
908         } else
909                 node = element_root;
910
911         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
912                                                 append_path, &filter);
913 }
914
915 struct count_data {
916         enum connman_element_type type;
917         int count;
918 };
919
920 static gboolean count_element(GNode *node, gpointer user_data)
921 {
922         struct connman_element *element = node->data;
923         struct count_data *data = user_data;
924
925         DBG("element %p name %s", element, element->name);
926
927         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
928                 return FALSE;
929
930         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
931                                         data->type != element->type)
932                 return FALSE;
933
934         data->count++;
935
936         return FALSE;
937 }
938
939 int __connman_element_count(struct connman_element *element,
940                                         enum connman_element_type type)
941 {
942         struct count_data data = { type, 0 };
943         GNode *node;
944
945         DBG("");
946
947         if (element != NULL) {
948                 node = g_node_find(element_root, G_PRE_ORDER,
949                                                 G_TRAVERSE_ALL, element);
950                 if (node == NULL)
951                         return 0;
952         } else
953                 node = element_root;
954
955         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
956                                                 count_element, &data);
957
958         return data.count;
959 }
960
961 static gint compare_priority(gconstpointer a, gconstpointer b)
962 {
963         const struct connman_driver *driver1 = a;
964         const struct connman_driver *driver2 = b;
965
966         return driver2->priority - driver1->priority;
967 }
968
969 static gboolean match_driver(struct connman_element *element,
970                                         struct connman_driver *driver)
971 {
972         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
973                 return FALSE;
974
975         if (element->type != driver->type &&
976                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
977                 return FALSE;
978
979         if (element->subtype == driver->subtype ||
980                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
981                 return TRUE;
982
983         return FALSE;
984 }
985
986 static void enable_element(struct connman_element *element)
987 {
988         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
989                 return;
990
991         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
992                 return;
993
994         if (element->driver && element->driver->enable) {
995                 if (element->driver->enable(element) == 0) {
996                         element->enabled = TRUE;
997                         emit_enabled_signal(connection, element);
998                 }
999         }
1000 }
1001
1002 static gboolean probe_driver(GNode *node, gpointer data)
1003 {
1004         struct connman_element *element = node->data;
1005         struct connman_driver *driver = data;
1006
1007         DBG("element %p name %s", element, element->name);
1008
1009         if (!element->driver && match_driver(element, driver) == TRUE) {
1010                 if (driver->probe(element) < 0)
1011                         return FALSE;
1012
1013                 __connman_element_lock(element);
1014                 element->driver = driver;
1015                 __connman_element_unlock(element);
1016
1017                 enable_element(element);
1018         }
1019
1020         return FALSE;
1021 }
1022
1023 void __connman_driver_rescan(struct connman_driver *driver)
1024 {
1025         DBG("driver %p name %s", driver, driver->name);
1026
1027         if (!driver->probe)
1028                 return;
1029
1030         if (element_root != NULL)
1031                 g_node_traverse(element_root, G_PRE_ORDER,
1032                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
1033 }
1034
1035 /**
1036  * connman_driver_register:
1037  * @driver: driver definition
1038  *
1039  * Register a new driver
1040  *
1041  * Returns: %0 on success
1042  */
1043 int connman_driver_register(struct connman_driver *driver)
1044 {
1045         DBG("driver %p name %s", driver, driver->name);
1046
1047         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
1048                 return -EINVAL;
1049
1050         if (!driver->probe)
1051                 return -EINVAL;
1052
1053         driver_list = g_slist_insert_sorted(driver_list, driver,
1054                                                         compare_priority);
1055
1056         if (element_root != NULL)
1057                 g_node_traverse(element_root, G_PRE_ORDER,
1058                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
1059
1060         return 0;
1061 }
1062
1063 static void disable_element(struct connman_element *element)
1064 {
1065         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
1066                 return;
1067
1068         if (element->enabled == FALSE)
1069                 return;
1070
1071         if (element->driver && element->driver->disable) {
1072                 if (element->driver->disable(element) == 0) {
1073                         element->enabled = FALSE;
1074                         emit_enabled_signal(connection, element);
1075                 }
1076         }
1077 }
1078
1079 static gboolean remove_driver(GNode *node, gpointer data)
1080 {
1081         struct connman_element *element = node->data;
1082         struct connman_driver *driver = data;
1083
1084         DBG("element %p name %s", element, element->name);
1085
1086         if (element->driver == driver) {
1087                 disable_element(element);
1088
1089                 if (driver->remove)
1090                         driver->remove(element);
1091
1092                 __connman_element_lock(element);
1093                 element->driver = NULL;
1094                 __connman_element_unlock(element);
1095         }
1096
1097         return FALSE;
1098 }
1099
1100 /**
1101  * connman_driver_unregister:
1102  * @driver: driver definition
1103  *
1104  * Remove a previously registered driver
1105  */
1106 void connman_driver_unregister(struct connman_driver *driver)
1107 {
1108         DBG("driver %p name %s", driver, driver->name);
1109
1110         driver_list = g_slist_remove(driver_list, driver);
1111
1112         if (element_root != NULL)
1113                 g_node_traverse(element_root, G_POST_ORDER,
1114                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
1115 }
1116
1117 /**
1118  * connman_element_create:
1119  * @name: element name
1120  *
1121  * Allocate a new element and assign the given #name to it. If the name
1122  * is #NULL, it will be later on created based on the element type.
1123  *
1124  * Returns: a newly-allocated #connman_element structure
1125  */
1126 struct connman_element *connman_element_create(const char *name)
1127 {
1128         struct connman_element *element;
1129
1130         element = g_try_new0(struct connman_element, 1);
1131         if (element == NULL)
1132                 return NULL;
1133
1134         DBG("element %p", element);
1135
1136         element->refcount = 1;
1137
1138         element->name    = g_strdup(name);
1139         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
1140         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
1141         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
1142         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
1143         element->index   = -1;
1144         element->enabled = FALSE;
1145
1146         return element;
1147 }
1148
1149 struct connman_element *connman_element_ref(struct connman_element *element)
1150 {
1151         DBG("element %p name %s refcount %d", element, element->name,
1152                                 g_atomic_int_get(&element->refcount) + 1);
1153
1154         g_atomic_int_inc(&element->refcount);
1155
1156         return element;
1157 }
1158
1159 static void free_properties(struct connman_element *element)
1160 {
1161         GSList *list;
1162
1163         DBG("element %p name %s", element, element->name);
1164
1165         __connman_element_lock(element);
1166
1167         for (list = element->properties; list; list = list->next) {
1168                 struct connman_property *property = list->data;
1169
1170                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1171                         g_free(property->value);
1172
1173                 g_free(property->name);
1174                 g_free(property);
1175         }
1176
1177         g_slist_free(element->properties);
1178
1179         element->properties = NULL;
1180
1181         __connman_element_unlock(element);
1182 }
1183
1184 void connman_element_unref(struct connman_element *element)
1185 {
1186         DBG("element %p name %s refcount %d", element, element->name,
1187                                 g_atomic_int_get(&element->refcount) - 1);
1188
1189         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
1190                 free_properties(element);
1191                 g_free(element->ipv4.address);
1192                 g_free(element->ipv4.netmask);
1193                 g_free(element->ipv4.gateway);
1194                 g_free(element->ipv4.network);
1195                 g_free(element->ipv4.broadcast);
1196                 g_free(element->ipv4.nameserver);
1197                 g_free(element->devname);
1198                 g_free(element->path);
1199                 g_free(element->name);
1200                 g_free(element);
1201         }
1202 }
1203
1204 int connman_element_add_static_property(struct connman_element *element,
1205                                 const char *name, int type, const void *value)
1206 {
1207         struct connman_property *property;
1208
1209         DBG("element %p name %s", element, element->name);
1210
1211         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1212                 return -EINVAL;
1213
1214         property = g_try_new0(struct connman_property, 1);
1215         if (property == NULL)
1216                 return -ENOMEM;
1217
1218         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
1219         property->id    = CONNMAN_PROPERTY_ID_INVALID;
1220         property->name  = g_strdup(name);
1221         property->type  = type;
1222
1223         DBG("name %s type %d value %p", name, type, value);
1224
1225         switch (type) {
1226         case DBUS_TYPE_STRING:
1227                 property->value = g_strdup(*((const char **) value));
1228                 break;
1229         case DBUS_TYPE_BYTE:
1230                 property->value = g_try_malloc(1);
1231                 if (property->value != NULL)
1232                         memcpy(property->value, value, 1);
1233                 break;
1234         }
1235
1236         __connman_element_lock(element);
1237         element->properties = g_slist_append(element->properties, property);
1238         __connman_element_unlock(element);
1239
1240         return 0;
1241 }
1242
1243 static void emit_property_changed(DBusConnection *conn,
1244                                 struct connman_element *element,
1245                                 const char *name, int type, const void *data)
1246 {
1247         DBusMessage *signal;
1248         DBusMessageIter entry, value;
1249         const char *iface, *sig;
1250
1251         DBG("conn %p", conn);
1252
1253         switch (element->type) {
1254         case CONNMAN_ELEMENT_TYPE_DEVICE:
1255                 iface = CONNMAN_DEVICE_INTERFACE;
1256                 break;
1257         case CONNMAN_ELEMENT_TYPE_NETWORK:
1258                 iface = CONNMAN_NETWORK_INTERFACE;
1259                 break;
1260         case CONNMAN_ELEMENT_TYPE_CONNECTION:
1261                 iface = CONNMAN_CONNECTION_INTERFACE;
1262                 break;
1263         default:
1264                 return;
1265         }
1266
1267         signal = dbus_message_new_signal(element->path,
1268                                                 iface, "PropertyChanged");
1269         if (signal == NULL)
1270                 return;
1271
1272         dbus_message_iter_init_append(signal, &entry);
1273
1274         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1275
1276         switch (type) {
1277         case DBUS_TYPE_STRING:
1278                 sig = DBUS_TYPE_STRING_AS_STRING;
1279                 break;
1280         case DBUS_TYPE_BYTE:
1281                 sig = DBUS_TYPE_BYTE_AS_STRING;
1282                 break;
1283         default:
1284                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1285                 break;
1286         }
1287
1288         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1289                                                         sig, &value);
1290         dbus_message_iter_append_basic(&value, type, data);
1291         dbus_message_iter_close_container(&entry, &value);
1292
1293         g_dbus_send_message(conn, signal);
1294 }
1295
1296 int connman_element_set_static_property(struct connman_element *element,
1297                                 const char *name, int type, const void *value)
1298 {
1299         GSList *list;
1300
1301         DBG("element %p name %s", element, element->name);
1302
1303         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1304                 return -EINVAL;
1305
1306         __connman_element_lock(element);
1307
1308         for (list = element->properties; list; list = list->next) {
1309                 struct connman_property *property = list->data;
1310
1311                 if (g_str_equal(property->name, name) == FALSE)
1312                         continue;
1313
1314                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1315                         continue;
1316
1317                 property->type = type;
1318                 g_free(property->value);
1319
1320                 switch (type) {
1321                 case DBUS_TYPE_STRING:
1322                         property->value = g_strdup(*((const char **) value));
1323                         break;
1324                 case DBUS_TYPE_BYTE:
1325                         property->value = g_try_malloc(1);
1326                         if (property->value != NULL)
1327                                 memcpy(property->value, value, 1);
1328                         break;
1329                 }
1330         }
1331
1332         __connman_element_unlock(element);
1333
1334         emit_property_changed(connection, element, name, type, value);
1335
1336         return 0;
1337 }
1338
1339 int connman_element_add_static_array_property(struct connman_element *element,
1340                         const char *name, int type, const void *value, int len)
1341 {
1342         struct connman_property *property;
1343
1344         DBG("element %p name %s", element, element->name);
1345
1346         if (type != DBUS_TYPE_BYTE)
1347                 return -EINVAL;
1348
1349         property = g_try_new0(struct connman_property, 1);
1350         if (property == NULL)
1351                 return -ENOMEM;
1352
1353         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1354         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1355         property->name    = g_strdup(name);
1356         property->type    = DBUS_TYPE_ARRAY;
1357         property->subtype = type;
1358
1359         DBG("name %s type %d value %p", name, type, value);
1360
1361         switch (type) {
1362         case DBUS_TYPE_BYTE:
1363                 property->value = g_try_malloc(len);
1364                 if (property->value != NULL) {
1365                         memcpy(property->value,
1366                                 *((const unsigned char **) value), len);
1367                         property->size = len;
1368                 }
1369                 break;
1370         }
1371
1372         __connman_element_lock(element);
1373         element->properties = g_slist_append(element->properties, property);
1374         __connman_element_unlock(element);
1375
1376         return 0;
1377 }
1378
1379 static void *get_reference_value(struct connman_element *element,
1380                                                 enum connman_property_id id)
1381 {
1382         GSList *list;
1383
1384         DBG("element %p name %s", element, element->name);
1385
1386         for (list = element->properties; list; list = list->next) {
1387                 struct connman_property *property = list->data;
1388
1389                 if (property->id != id)
1390                         continue;
1391
1392                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1393                         return property->value;
1394         }
1395
1396         if (element->parent == NULL)
1397                 return NULL;
1398
1399         return get_reference_value(element->parent, id);
1400 }
1401
1402 static void set_reference_properties(struct connman_element *element)
1403 {
1404         GSList *list;
1405
1406         DBG("element %p name %s", element, element->name);
1407
1408         for (list = element->properties; list; list = list->next) {
1409                 struct connman_property *property = list->data;
1410
1411                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1412                         continue;
1413
1414                 property->value = get_reference_value(element->parent,
1415                                                                 property->id);
1416         }
1417 }
1418
1419 static struct connman_property *create_property(struct connman_element *element,
1420                                                 enum connman_property_id id)
1421 {
1422         struct connman_property *property;
1423         GSList *list;
1424
1425         DBG("element %p name %s", element, element->name);
1426
1427         __connman_element_lock(element);
1428
1429         for (list = element->properties; list; list = list->next) {
1430                 property = list->data;
1431
1432                 if (property->id == id)
1433                         goto unlock;
1434         }
1435
1436         property = g_try_new0(struct connman_property, 1);
1437         if (property == NULL)
1438                 goto unlock;
1439
1440         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1441         property->id    = id;
1442         property->name  = g_strdup(propid2name(id));
1443         property->type  = propid2type(id);
1444
1445         if (property->name == NULL) {
1446                 g_free(property);
1447                 property = NULL;
1448                 goto unlock;
1449         }
1450
1451         element->properties = g_slist_append(element->properties, property);
1452
1453 unlock:
1454         __connman_element_unlock(element);
1455
1456         return property;
1457 }
1458
1459 static void create_default_properties(struct connman_element *element)
1460 {
1461         struct connman_property *property;
1462         int i;
1463
1464         DBG("element %p name %s", element, element->name);
1465
1466         for (i = 0; propid_table[i].name; i++) {
1467                 DBG("property %s", propid_table[i].name);
1468
1469                 property = create_property(element, propid_table[i].id);
1470
1471                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1472
1473                 if (propid_table[i].type != DBUS_TYPE_STRING)
1474                         continue;
1475
1476                 if (propid_table[i].value)
1477                         property->value = g_strdup(propid_table[i].value);
1478                 else
1479                         property->value = g_strdup("");
1480         }
1481 }
1482
1483 static int define_properties_valist(struct connman_element *element,
1484                                                                 va_list args)
1485 {
1486         enum connman_property_id id;
1487
1488         DBG("element %p name %s", element, element->name);
1489
1490         id = va_arg(args, enum connman_property_id);
1491
1492         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1493
1494                 DBG("property %d", id);
1495
1496                 create_property(element, id);
1497
1498                 id = va_arg(args, enum connman_property_id);
1499         }
1500
1501         return 0;
1502 }
1503
1504 /**
1505  * connman_element_define_properties:
1506  * @element: an element
1507  * @varargs: list of property identifiers
1508  *
1509  * Define the valid properties for an element.
1510  *
1511  * Returns: %0 on success
1512  */
1513 int connman_element_define_properties(struct connman_element *element, ...)
1514 {
1515         va_list args;
1516         int err;
1517
1518         DBG("element %p name %s", element, element->name);
1519
1520         va_start(args, element);
1521
1522         err = define_properties_valist(element, args);
1523
1524         va_end(args);
1525
1526         return err;
1527 }
1528
1529 int connman_element_create_property(struct connman_element *element,
1530                                                 const char *name, int type)
1531 {
1532         return -EIO;
1533 }
1534
1535 int connman_element_set_property(struct connman_element *element,
1536                                 enum connman_property_id id, const void *value)
1537 {
1538         switch (id) {
1539         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1540                 __connman_element_lock(element);
1541                 g_free(element->ipv4.address);
1542                 element->ipv4.address = g_strdup(*((const char **) value));
1543                 __connman_element_unlock(element);
1544                 break;
1545         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1546                 __connman_element_lock(element);
1547                 g_free(element->ipv4.netmask);
1548                 element->ipv4.netmask = g_strdup(*((const char **) value));
1549                 __connman_element_unlock(element);
1550                 break;
1551         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1552                 __connman_element_lock(element);
1553                 g_free(element->ipv4.gateway);
1554                 element->ipv4.gateway = g_strdup(*((const char **) value));
1555                 __connman_element_unlock(element);
1556                 break;
1557         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1558                 __connman_element_lock(element);
1559                 g_free(element->ipv4.broadcast);
1560                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1561                 __connman_element_unlock(element);
1562                 break;
1563         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1564                 __connman_element_lock(element);
1565                 g_free(element->ipv4.nameserver);
1566                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1567                 __connman_element_unlock(element);
1568                 break;
1569         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1570                 __connman_element_lock(element);
1571                 g_free(element->wifi.security);
1572                 element->wifi.security = g_strdup(*((const char **) value));
1573                 __connman_element_unlock(element);
1574                 break;
1575         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1576                 __connman_element_lock(element);
1577                 g_free(element->wifi.passphrase);
1578                 element->wifi.passphrase = g_strdup(*((const char **) value));
1579                 __connman_element_unlock(element);
1580                 break;
1581         default:
1582                 return -EINVAL;
1583         }
1584
1585         return 0;
1586 }
1587
1588 int connman_element_get_value(struct connman_element *element,
1589                                 enum connman_property_id id, void *value)
1590 {
1591         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1592                 return -EINVAL;
1593
1594         switch (id) {
1595         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1596                 if (element->ipv4.address == NULL)
1597                         return connman_element_get_value(element->parent,
1598                                                                 id, value);
1599                 __connman_element_lock(element);
1600                 *((char **) value) = element->ipv4.address;
1601                 __connman_element_unlock(element);
1602                 break;
1603         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1604                 if (element->ipv4.netmask == NULL)
1605                         return connman_element_get_value(element->parent,
1606                                                                 id, value);
1607                 __connman_element_lock(element);
1608                 *((char **) value) = element->ipv4.netmask;
1609                 __connman_element_unlock(element);
1610                 break;
1611         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1612                 if (element->ipv4.gateway == NULL)
1613                         return connman_element_get_value(element->parent,
1614                                                                 id, value);
1615                 __connman_element_lock(element);
1616                 *((char **) value) = element->ipv4.gateway;
1617                 __connman_element_unlock(element);
1618                 break;
1619         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1620                 if (element->ipv4.broadcast == NULL)
1621                         return connman_element_get_value(element->parent,
1622                                                                 id, value);
1623                 __connman_element_lock(element);
1624                 *((char **) value) = element->ipv4.broadcast;
1625                 __connman_element_unlock(element);
1626                 break;
1627         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1628                 if (element->ipv4.nameserver == NULL)
1629                         return connman_element_get_value(element->parent,
1630                                                                 id, value);
1631                 __connman_element_lock(element);
1632                 *((char **) value) = element->ipv4.nameserver;
1633                 __connman_element_unlock(element);
1634                 break;
1635         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1636                 if (element->wifi.security == NULL)
1637                         return connman_element_get_value(element->parent,
1638                                                                 id, value);
1639                 __connman_element_lock(element);
1640                 *((char **) value) = element->wifi.security;
1641                 __connman_element_unlock(element);
1642                 break;
1643         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1644                 if (element->wifi.passphrase == NULL)
1645                         return connman_element_get_value(element->parent,
1646                                                                 id, value);
1647                 __connman_element_lock(element);
1648                 *((char **) value) = element->wifi.passphrase;
1649                 __connman_element_unlock(element);
1650                 break;
1651         default:
1652                 return -EINVAL;
1653         }
1654
1655         return 0;
1656 }
1657
1658 gboolean connman_element_get_static_property(struct connman_element *element,
1659                                                 const char *name, void *value)
1660 {
1661         GSList *list;
1662         gboolean found = FALSE;
1663
1664         DBG("element %p name %s", element, element->name);
1665
1666         __connman_element_lock(element);
1667
1668         for (list = element->properties; list; list = list->next) {
1669                 struct connman_property *property = list->data;
1670
1671                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1672                         continue;
1673
1674                 if (g_str_equal(property->name, name) == TRUE) {
1675                         switch (property->type) {
1676                         case DBUS_TYPE_STRING:
1677                                 *((char **) value) = property->value;
1678                                 found = TRUE;
1679                                 break;
1680                         }
1681                         break;
1682                 }
1683         }
1684
1685         __connman_element_unlock(element);
1686
1687         return found;
1688 }
1689
1690 gboolean connman_element_get_static_array_property(struct connman_element *element,
1691                                         const char *name, void *value, int *len)
1692 {
1693         GSList *list;
1694         gboolean found = FALSE;
1695
1696         DBG("element %p name %s", element, element->name);
1697
1698         __connman_element_lock(element);
1699
1700         for (list = element->properties; list; list = list->next) {
1701                 struct connman_property *property = list->data;
1702
1703                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1704                         continue;
1705
1706                 if (g_str_equal(property->name, name) == TRUE) {
1707                         *((char **) value) = property->value;
1708                         *len = property->size;
1709                         found = TRUE;
1710                         break;
1711                 }
1712         }
1713
1714         __connman_element_unlock(element);
1715
1716         return found;
1717 }
1718
1719 gboolean connman_element_match_static_property(struct connman_element *element,
1720                                         const char *name, const void *value)
1721 {
1722         GSList *list;
1723         gboolean result = FALSE;
1724
1725         DBG("element %p name %s", element, element->name);
1726
1727         __connman_element_lock(element);
1728
1729         for (list = element->properties; list; list = list->next) {
1730                 struct connman_property *property = list->data;
1731
1732                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1733                         continue;
1734
1735                 if (g_str_equal(property->name, name) == FALSE)
1736                         continue;
1737
1738                 if (property->type == DBUS_TYPE_STRING)
1739                         result = g_str_equal(property->value,
1740                                                 *((const char **) value));
1741
1742                 if (result == TRUE)
1743                         break;
1744         }
1745
1746         __connman_element_unlock(element);
1747
1748         return result;
1749 }
1750
1751 static void append_devices(DBusMessageIter *entry)
1752 {
1753         DBusMessageIter value, iter;
1754         const char *key = "Devices";
1755
1756         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1757
1758         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1759                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1760                                                                 &value);
1761
1762         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1763                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1764         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1765         dbus_message_iter_close_container(&value, &iter);
1766
1767         dbus_message_iter_close_container(entry, &value);
1768 }
1769
1770 static void emit_devices_signal(DBusConnection *conn)
1771 {
1772         DBusMessage *signal;
1773         DBusMessageIter entry;
1774
1775         DBG("conn %p", conn);
1776
1777         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1778                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1779         if (signal == NULL)
1780                 return;
1781
1782         dbus_message_iter_init_append(signal, &entry);
1783
1784         append_devices(&entry);
1785
1786         g_dbus_send_message(conn, signal);
1787 }
1788
1789 static void emit_networks_signal(DBusConnection *conn,
1790                                         struct connman_element *device)
1791 {
1792         DBusMessage *signal;
1793         DBusMessageIter entry;
1794
1795         DBG("conn %p", conn);
1796
1797         if (device == NULL)
1798                 return;
1799
1800         signal = dbus_message_new_signal(device->path,
1801                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1802         if (signal == NULL)
1803                 return;
1804
1805         dbus_message_iter_init_append(signal, &entry);
1806
1807         append_networks(device, &entry);
1808
1809         g_dbus_send_message(conn, signal);
1810 }
1811
1812 static void append_connections(DBusMessageIter *entry)
1813 {
1814         DBusMessageIter value, iter;
1815         const char *key = "Connections";
1816
1817         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1818
1819         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1820                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1821                                                                 &value);
1822
1823         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1824                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1825         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1826         dbus_message_iter_close_container(&value, &iter);
1827
1828         dbus_message_iter_close_container(entry, &value);
1829 }
1830
1831 static void emit_connections_signal(DBusConnection *conn)
1832 {
1833         DBusMessage *signal;
1834         DBusMessageIter entry;
1835
1836         DBG("conn %p", conn);
1837
1838         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1839                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1840         if (signal == NULL)
1841                 return;
1842
1843         dbus_message_iter_init_append(signal, &entry);
1844
1845         append_connections(&entry);
1846
1847         g_dbus_send_message(conn, signal);
1848 }
1849
1850 static void append_state(DBusMessageIter *entry, const char *state)
1851 {
1852         DBusMessageIter value;
1853         const char *key = "State";
1854
1855         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1856
1857         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1858                                         DBUS_TYPE_STRING_AS_STRING, &value);
1859         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1860         dbus_message_iter_close_container(entry, &value);
1861 }
1862
1863 static void emit_state_change(DBusConnection *conn, const char *state)
1864 {
1865         DBusMessage *signal;
1866         DBusMessageIter entry;
1867
1868         DBG("conn %p", conn);
1869
1870         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1871                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1872         if (signal == NULL)
1873                 return;
1874
1875         dbus_message_iter_init_append(signal, &entry);
1876
1877         append_state(&entry, state);
1878
1879         g_dbus_send_message(conn, signal);
1880 }
1881
1882 static void set_signal_strength(struct connman_element *connection)
1883 {
1884         struct connman_element *element = connection;
1885
1886         while (element != NULL) {
1887                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1888                         connection->strength = element->strength;
1889                         break;
1890                 }
1891
1892                 element = element->parent;
1893         }
1894 }
1895
1896 static void register_element(gpointer data, gpointer user_data)
1897 {
1898         struct connman_element *element = data;
1899         const gchar *basepath;
1900         GSList *list;
1901         GNode *node;
1902
1903         __connman_element_lock(element);
1904
1905         if (element->parent) {
1906                 node = g_node_find(element_root, G_PRE_ORDER,
1907                                         G_TRAVERSE_ALL, element->parent);
1908                 basepath = element->parent->path;
1909
1910                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1911                         element->subtype = element->parent->subtype;
1912         } else {
1913                 element->parent = element_root->data;
1914
1915                 node = element_root;
1916                 basepath = "";
1917         }
1918
1919         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1920
1921         set_reference_properties(element);
1922
1923         __connman_element_unlock(element);
1924
1925         DBG("element %p path %s", element, element->path);
1926
1927         __connman_element_load(element);
1928
1929         g_node_append_data(node, element);
1930
1931         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1932                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1933                 if (g_dbus_register_interface(connection, element->path,
1934                                         CONNMAN_DEVICE_INTERFACE,
1935                                         device_methods, element_signals,
1936                                         NULL, element, NULL) == FALSE)
1937                         connman_error("Failed to register %s device",
1938                                                                 element->path);
1939                 else
1940                         emit_devices_signal(connection);
1941         }
1942
1943         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1944                 if (g_dbus_register_interface(connection, element->path,
1945                                         CONNMAN_NETWORK_INTERFACE,
1946                                         network_methods, element_signals,
1947                                         NULL, element, NULL) == FALSE)
1948                         connman_error("Failed to register %s network",
1949                                                                 element->path);
1950                 else
1951                         emit_networks_signal(connection, element->parent);
1952         }
1953
1954         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1955                 if (g_dbus_register_interface(connection, element->path,
1956                                         CONNMAN_CONNECTION_INTERFACE,
1957                                         connection_methods, element_signals,
1958                                         NULL, element, NULL) == FALSE)
1959                         connman_error("Failed to register %s connection",
1960                                                                 element->path);
1961                 else {
1962                         set_signal_strength(element);
1963                         emit_connections_signal(connection);
1964                         emit_state_change(connection, "online");
1965                 }
1966         }
1967
1968         __connman_element_store(element);
1969
1970         for (list = driver_list; list; list = list->next) {
1971                 struct connman_driver *driver = list->data;
1972
1973                 if (match_driver(element, driver) == FALSE)
1974                         continue;
1975
1976                 DBG("driver %p name %s", driver, driver->name);
1977
1978                 if (driver->probe(element) == 0) {
1979                         __connman_element_lock(element);
1980                         element->driver = driver;
1981                         __connman_element_unlock(element);
1982
1983                         enable_element(element);
1984                         break;
1985                 }
1986         }
1987 }
1988
1989 /**
1990  * connman_element_register:
1991  * @element: the element to register
1992  * @parent: the parent to register the element with
1993  *
1994  * Register an element with the core. It will be register under the given
1995  * parent of if %NULL is provided under the root element.
1996  *
1997  * Returns: %0 on success
1998  */
1999 int connman_element_register(struct connman_element *element,
2000                                         struct connman_element *parent)
2001 {
2002         DBG("element %p name %s parent %p", element, element->name, parent);
2003
2004         if (element->devname == NULL)
2005                 element->devname = g_strdup(element->name);
2006
2007         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2008                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2009                 if (g_pattern_match_simple(device_filter,
2010                                                 element->devname) == FALSE) {
2011                         DBG("ignoring %s [%s] device", element->name,
2012                                                         element->devname);
2013                         return -EPERM;
2014                 }
2015         }
2016
2017         if (connman_element_ref(element) == NULL)
2018                 return -EINVAL;
2019
2020         __connman_element_lock(element);
2021
2022         if (element->name == NULL) {
2023                 element->name = g_strdup(type2string(element->type));
2024                 if (element->name == NULL) {
2025                         __connman_element_unlock(element);
2026                         return -EINVAL;
2027                 }
2028         }
2029
2030         element->parent = parent;
2031
2032         __connman_element_unlock(element);
2033
2034         register_element(element, NULL);
2035
2036         return 0;
2037 }
2038
2039 static gboolean remove_element(GNode *node, gpointer user_data)
2040 {
2041         struct connman_element *element = node->data;
2042         struct connman_element *root = user_data;
2043
2044         DBG("element %p name %s", element, element->name);
2045
2046         if (element == root)
2047                 return FALSE;
2048
2049         if (element->driver) {
2050                 disable_element(element);
2051
2052                 if (element->driver->remove)
2053                         element->driver->remove(element);
2054
2055                 __connman_element_lock(element);
2056                 element->driver = NULL;
2057                 __connman_element_unlock(element);
2058         }
2059
2060         if (node != NULL) {
2061                 g_node_unlink(node);
2062                 g_node_destroy(node);
2063         }
2064
2065         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
2066                 if (__connman_element_count(NULL,
2067                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
2068                         emit_state_change(connection, "offline");
2069                 emit_connections_signal(connection);
2070
2071                 g_dbus_unregister_interface(connection, element->path,
2072                                                 CONNMAN_CONNECTION_INTERFACE);
2073         }
2074
2075         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2076                 emit_networks_signal(connection, element->parent);
2077
2078                 g_dbus_unregister_interface(connection, element->path,
2079                                                 CONNMAN_NETWORK_INTERFACE);
2080         }
2081
2082         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2083                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2084                 emit_devices_signal(connection);
2085
2086                 g_dbus_unregister_interface(connection, element->path,
2087                                                 CONNMAN_DEVICE_INTERFACE);
2088         }
2089
2090         connman_element_unref(element);
2091
2092         return FALSE;
2093 }
2094
2095 void connman_element_unregister(struct connman_element *element)
2096 {
2097         GNode *node;
2098
2099         DBG("element %p name %s", element, element->name);
2100
2101         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2102
2103         if (node != NULL)
2104                 g_node_traverse(node, G_POST_ORDER,
2105                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
2106 }
2107
2108 void connman_element_unregister_children(struct connman_element *element)
2109 {
2110         GNode *node;
2111
2112         DBG("element %p name %s", element, element->name);
2113
2114         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2115
2116         if (node != NULL)
2117                 g_node_traverse(node, G_POST_ORDER,
2118                                 G_TRAVERSE_ALL, -1, remove_element, element);
2119 }
2120
2121 static gboolean update_element(GNode *node, gpointer user_data)
2122 {
2123         struct connman_element *element = node->data;
2124         struct connman_element *root = user_data;
2125
2126         DBG("element %p name %s", element, element->name);
2127
2128         if (element->driver && element->driver->update)
2129                 element->driver->update(element);
2130
2131         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION &&
2132                                 root->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2133                 if (element->strength != root->strength) {
2134                         element->strength = root->strength;
2135                         emit_property_changed(connection, element, "Strength",
2136                                         DBUS_TYPE_BYTE, &element->strength);
2137                 }
2138         }
2139
2140         return FALSE;
2141 }
2142
2143 void connman_element_update(struct connman_element *element)
2144 {
2145         GNode *node;
2146
2147         DBG("element %p name %s", element, element->name);
2148
2149         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2150
2151         if (node != NULL)
2152                 g_node_traverse(node, G_PRE_ORDER,
2153                                 G_TRAVERSE_ALL, -1, update_element, element);
2154 }
2155
2156 int connman_element_set_enabled(struct connman_element *element,
2157                                                         gboolean enabled)
2158 {
2159         if (element->enabled == enabled)
2160                 return 0;
2161
2162         element->enabled = enabled;
2163
2164         emit_enabled_signal(connection, element);
2165
2166         return 0;
2167 }
2168
2169 int connman_element_set_scanning(struct connman_element *element,
2170                                                         gboolean scanning)
2171 {
2172         if (element->scanning == scanning)
2173                 return 0;
2174
2175         element->scanning = scanning;
2176
2177         emit_scanning_signal(connection, element);
2178
2179         return 0;
2180 }
2181
2182 int __connman_element_init(DBusConnection *conn, const char *device)
2183 {
2184         struct connman_element *element;
2185
2186         DBG("conn %p", conn);
2187
2188         connection = dbus_connection_ref(conn);
2189         if (connection == NULL)
2190                 return -EIO;
2191
2192         device_filter = g_strdup(device);
2193
2194         element = connman_element_create("root");
2195
2196         element->path = g_strdup("/");
2197         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
2198
2199         create_default_properties(element);
2200
2201         element_root = g_node_new(element);
2202
2203         __connman_device_init();
2204
2205         return 0;
2206 }
2207
2208 static gboolean free_driver(GNode *node, gpointer data)
2209 {
2210         struct connman_element *element = node->data;
2211
2212         DBG("element %p name %s", element, element->name);
2213
2214         if (element->driver) {
2215                 disable_element(element);
2216
2217                 if (element->driver->remove)
2218                         element->driver->remove(element);
2219
2220                 __connman_element_lock(element);
2221                 element->driver = NULL;
2222                 __connman_element_unlock(element);
2223         }
2224
2225         return FALSE;
2226 }
2227
2228 static gboolean free_node(GNode *node, gpointer data)
2229 {
2230         struct connman_element *element = node->data;
2231
2232         DBG("element %p name %s", element, element->name);
2233
2234         if (g_node_depth(node) > 1)
2235                 connman_element_unregister(element);
2236
2237         return FALSE;
2238 }
2239
2240 void __connman_element_cleanup(void)
2241 {
2242         DBG("");
2243
2244         __connman_device_cleanup();
2245
2246         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2247                                                         free_driver, NULL);
2248
2249         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2250                                                         free_node, NULL);
2251
2252         g_node_destroy(element_root);
2253         element_root = NULL;
2254
2255         g_free(device_filter);
2256
2257         dbus_connection_unref(connection);
2258 }