Iterate over the Bluetooth Devices property
[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 (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->devpath);
1199                 g_free(element->path);
1200                 g_free(element->name);
1201                 g_free(element);
1202         }
1203 }
1204
1205 int connman_element_add_static_property(struct connman_element *element,
1206                                 const char *name, int type, const void *value)
1207 {
1208         struct connman_property *property;
1209
1210         DBG("element %p name %s", element, element->name);
1211
1212         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1213                 return -EINVAL;
1214
1215         property = g_try_new0(struct connman_property, 1);
1216         if (property == NULL)
1217                 return -ENOMEM;
1218
1219         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
1220         property->id    = CONNMAN_PROPERTY_ID_INVALID;
1221         property->name  = g_strdup(name);
1222         property->type  = type;
1223
1224         DBG("name %s type %d value %p", name, type, value);
1225
1226         switch (type) {
1227         case DBUS_TYPE_STRING:
1228                 property->value = g_strdup(*((const char **) value));
1229                 break;
1230         case DBUS_TYPE_BYTE:
1231                 property->value = g_try_malloc(1);
1232                 if (property->value != NULL)
1233                         memcpy(property->value, value, 1);
1234                 break;
1235         }
1236
1237         __connman_element_lock(element);
1238         element->properties = g_slist_append(element->properties, property);
1239         __connman_element_unlock(element);
1240
1241         return 0;
1242 }
1243
1244 static void emit_property_changed(DBusConnection *conn,
1245                                 struct connman_element *element,
1246                                 const char *name, int type, const void *data)
1247 {
1248         DBusMessage *signal;
1249         DBusMessageIter entry, value;
1250         const char *iface, *sig;
1251
1252         DBG("conn %p", conn);
1253
1254         switch (element->type) {
1255         case CONNMAN_ELEMENT_TYPE_DEVICE:
1256                 iface = CONNMAN_DEVICE_INTERFACE;
1257                 break;
1258         case CONNMAN_ELEMENT_TYPE_NETWORK:
1259                 iface = CONNMAN_NETWORK_INTERFACE;
1260                 break;
1261         case CONNMAN_ELEMENT_TYPE_CONNECTION:
1262                 iface = CONNMAN_CONNECTION_INTERFACE;
1263                 break;
1264         default:
1265                 return;
1266         }
1267
1268         signal = dbus_message_new_signal(element->path,
1269                                                 iface, "PropertyChanged");
1270         if (signal == NULL)
1271                 return;
1272
1273         dbus_message_iter_init_append(signal, &entry);
1274
1275         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1276
1277         switch (type) {
1278         case DBUS_TYPE_STRING:
1279                 sig = DBUS_TYPE_STRING_AS_STRING;
1280                 break;
1281         case DBUS_TYPE_BYTE:
1282                 sig = DBUS_TYPE_BYTE_AS_STRING;
1283                 break;
1284         default:
1285                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1286                 break;
1287         }
1288
1289         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1290                                                         sig, &value);
1291         dbus_message_iter_append_basic(&value, type, data);
1292         dbus_message_iter_close_container(&entry, &value);
1293
1294         g_dbus_send_message(conn, signal);
1295 }
1296
1297 int connman_element_set_static_property(struct connman_element *element,
1298                                 const char *name, int type, const void *value)
1299 {
1300         GSList *list;
1301
1302         DBG("element %p name %s", element, element->name);
1303
1304         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1305                 return -EINVAL;
1306
1307         __connman_element_lock(element);
1308
1309         for (list = element->properties; list; list = list->next) {
1310                 struct connman_property *property = list->data;
1311
1312                 if (g_str_equal(property->name, name) == FALSE)
1313                         continue;
1314
1315                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1316                         continue;
1317
1318                 property->type = type;
1319                 g_free(property->value);
1320
1321                 switch (type) {
1322                 case DBUS_TYPE_STRING:
1323                         property->value = g_strdup(*((const char **) value));
1324                         break;
1325                 case DBUS_TYPE_BYTE:
1326                         property->value = g_try_malloc(1);
1327                         if (property->value != NULL)
1328                                 memcpy(property->value, value, 1);
1329                         break;
1330                 }
1331         }
1332
1333         __connman_element_unlock(element);
1334
1335         emit_property_changed(connection, element, name, type, value);
1336
1337         return 0;
1338 }
1339
1340 int connman_element_add_static_array_property(struct connman_element *element,
1341                         const char *name, int type, const void *value, int len)
1342 {
1343         struct connman_property *property;
1344
1345         DBG("element %p name %s", element, element->name);
1346
1347         if (type != DBUS_TYPE_BYTE)
1348                 return -EINVAL;
1349
1350         property = g_try_new0(struct connman_property, 1);
1351         if (property == NULL)
1352                 return -ENOMEM;
1353
1354         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1355         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1356         property->name    = g_strdup(name);
1357         property->type    = DBUS_TYPE_ARRAY;
1358         property->subtype = type;
1359
1360         DBG("name %s type %d value %p", name, type, value);
1361
1362         switch (type) {
1363         case DBUS_TYPE_BYTE:
1364                 property->value = g_try_malloc(len);
1365                 if (property->value != NULL) {
1366                         memcpy(property->value,
1367                                 *((const unsigned char **) value), len);
1368                         property->size = len;
1369                 }
1370                 break;
1371         }
1372
1373         __connman_element_lock(element);
1374         element->properties = g_slist_append(element->properties, property);
1375         __connman_element_unlock(element);
1376
1377         return 0;
1378 }
1379
1380 static void *get_reference_value(struct connman_element *element,
1381                                                 enum connman_property_id id)
1382 {
1383         GSList *list;
1384
1385         DBG("element %p name %s", element, element->name);
1386
1387         for (list = element->properties; list; list = list->next) {
1388                 struct connman_property *property = list->data;
1389
1390                 if (property->id != id)
1391                         continue;
1392
1393                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1394                         return property->value;
1395         }
1396
1397         if (element->parent == NULL)
1398                 return NULL;
1399
1400         return get_reference_value(element->parent, id);
1401 }
1402
1403 static void set_reference_properties(struct connman_element *element)
1404 {
1405         GSList *list;
1406
1407         DBG("element %p name %s", element, element->name);
1408
1409         for (list = element->properties; list; list = list->next) {
1410                 struct connman_property *property = list->data;
1411
1412                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1413                         continue;
1414
1415                 property->value = get_reference_value(element->parent,
1416                                                                 property->id);
1417         }
1418 }
1419
1420 static struct connman_property *create_property(struct connman_element *element,
1421                                                 enum connman_property_id id)
1422 {
1423         struct connman_property *property;
1424         GSList *list;
1425
1426         DBG("element %p name %s", element, element->name);
1427
1428         __connman_element_lock(element);
1429
1430         for (list = element->properties; list; list = list->next) {
1431                 property = list->data;
1432
1433                 if (property->id == id)
1434                         goto unlock;
1435         }
1436
1437         property = g_try_new0(struct connman_property, 1);
1438         if (property == NULL)
1439                 goto unlock;
1440
1441         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1442         property->id    = id;
1443         property->name  = g_strdup(propid2name(id));
1444         property->type  = propid2type(id);
1445
1446         if (property->name == NULL) {
1447                 g_free(property);
1448                 property = NULL;
1449                 goto unlock;
1450         }
1451
1452         element->properties = g_slist_append(element->properties, property);
1453
1454 unlock:
1455         __connman_element_unlock(element);
1456
1457         return property;
1458 }
1459
1460 static void create_default_properties(struct connman_element *element)
1461 {
1462         struct connman_property *property;
1463         int i;
1464
1465         DBG("element %p name %s", element, element->name);
1466
1467         for (i = 0; propid_table[i].name; i++) {
1468                 DBG("property %s", propid_table[i].name);
1469
1470                 property = create_property(element, propid_table[i].id);
1471
1472                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1473
1474                 if (propid_table[i].type != DBUS_TYPE_STRING)
1475                         continue;
1476
1477                 if (propid_table[i].value)
1478                         property->value = g_strdup(propid_table[i].value);
1479                 else
1480                         property->value = g_strdup("");
1481         }
1482 }
1483
1484 static int define_properties_valist(struct connman_element *element,
1485                                                                 va_list args)
1486 {
1487         enum connman_property_id id;
1488
1489         DBG("element %p name %s", element, element->name);
1490
1491         id = va_arg(args, enum connman_property_id);
1492
1493         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1494
1495                 DBG("property %d", id);
1496
1497                 create_property(element, id);
1498
1499                 id = va_arg(args, enum connman_property_id);
1500         }
1501
1502         return 0;
1503 }
1504
1505 /**
1506  * connman_element_define_properties:
1507  * @element: an element
1508  * @varargs: list of property identifiers
1509  *
1510  * Define the valid properties for an element.
1511  *
1512  * Returns: %0 on success
1513  */
1514 int connman_element_define_properties(struct connman_element *element, ...)
1515 {
1516         va_list args;
1517         int err;
1518
1519         DBG("element %p name %s", element, element->name);
1520
1521         va_start(args, element);
1522
1523         err = define_properties_valist(element, args);
1524
1525         va_end(args);
1526
1527         return err;
1528 }
1529
1530 int connman_element_create_property(struct connman_element *element,
1531                                                 const char *name, int type)
1532 {
1533         return -EIO;
1534 }
1535
1536 int connman_element_set_property(struct connman_element *element,
1537                                 enum connman_property_id id, const void *value)
1538 {
1539         switch (id) {
1540         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1541                 __connman_element_lock(element);
1542                 g_free(element->ipv4.address);
1543                 element->ipv4.address = g_strdup(*((const char **) value));
1544                 __connman_element_unlock(element);
1545                 break;
1546         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1547                 __connman_element_lock(element);
1548                 g_free(element->ipv4.netmask);
1549                 element->ipv4.netmask = g_strdup(*((const char **) value));
1550                 __connman_element_unlock(element);
1551                 break;
1552         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1553                 __connman_element_lock(element);
1554                 g_free(element->ipv4.gateway);
1555                 element->ipv4.gateway = g_strdup(*((const char **) value));
1556                 __connman_element_unlock(element);
1557                 break;
1558         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1559                 __connman_element_lock(element);
1560                 g_free(element->ipv4.broadcast);
1561                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1562                 __connman_element_unlock(element);
1563                 break;
1564         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1565                 __connman_element_lock(element);
1566                 g_free(element->ipv4.nameserver);
1567                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1568                 __connman_element_unlock(element);
1569                 break;
1570         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1571                 __connman_element_lock(element);
1572                 g_free(element->wifi.security);
1573                 element->wifi.security = g_strdup(*((const char **) value));
1574                 __connman_element_unlock(element);
1575                 break;
1576         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1577                 __connman_element_lock(element);
1578                 g_free(element->wifi.passphrase);
1579                 element->wifi.passphrase = g_strdup(*((const char **) value));
1580                 __connman_element_unlock(element);
1581                 break;
1582         default:
1583                 return -EINVAL;
1584         }
1585
1586         return 0;
1587 }
1588
1589 int connman_element_get_value(struct connman_element *element,
1590                                 enum connman_property_id id, void *value)
1591 {
1592         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1593                 return -EINVAL;
1594
1595         switch (id) {
1596         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1597                 if (element->ipv4.address == NULL)
1598                         return connman_element_get_value(element->parent,
1599                                                                 id, value);
1600                 __connman_element_lock(element);
1601                 *((char **) value) = element->ipv4.address;
1602                 __connman_element_unlock(element);
1603                 break;
1604         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1605                 if (element->ipv4.netmask == NULL)
1606                         return connman_element_get_value(element->parent,
1607                                                                 id, value);
1608                 __connman_element_lock(element);
1609                 *((char **) value) = element->ipv4.netmask;
1610                 __connman_element_unlock(element);
1611                 break;
1612         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1613                 if (element->ipv4.gateway == NULL)
1614                         return connman_element_get_value(element->parent,
1615                                                                 id, value);
1616                 __connman_element_lock(element);
1617                 *((char **) value) = element->ipv4.gateway;
1618                 __connman_element_unlock(element);
1619                 break;
1620         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1621                 if (element->ipv4.broadcast == NULL)
1622                         return connman_element_get_value(element->parent,
1623                                                                 id, value);
1624                 __connman_element_lock(element);
1625                 *((char **) value) = element->ipv4.broadcast;
1626                 __connman_element_unlock(element);
1627                 break;
1628         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1629                 if (element->ipv4.nameserver == NULL)
1630                         return connman_element_get_value(element->parent,
1631                                                                 id, value);
1632                 __connman_element_lock(element);
1633                 *((char **) value) = element->ipv4.nameserver;
1634                 __connman_element_unlock(element);
1635                 break;
1636         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1637                 if (element->wifi.security == NULL)
1638                         return connman_element_get_value(element->parent,
1639                                                                 id, value);
1640                 __connman_element_lock(element);
1641                 *((char **) value) = element->wifi.security;
1642                 __connman_element_unlock(element);
1643                 break;
1644         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1645                 if (element->wifi.passphrase == NULL)
1646                         return connman_element_get_value(element->parent,
1647                                                                 id, value);
1648                 __connman_element_lock(element);
1649                 *((char **) value) = element->wifi.passphrase;
1650                 __connman_element_unlock(element);
1651                 break;
1652         default:
1653                 return -EINVAL;
1654         }
1655
1656         return 0;
1657 }
1658
1659 gboolean connman_element_get_static_property(struct connman_element *element,
1660                                                 const char *name, void *value)
1661 {
1662         GSList *list;
1663         gboolean found = FALSE;
1664
1665         DBG("element %p name %s", element, element->name);
1666
1667         __connman_element_lock(element);
1668
1669         for (list = element->properties; list; list = list->next) {
1670                 struct connman_property *property = list->data;
1671
1672                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1673                         continue;
1674
1675                 if (g_str_equal(property->name, name) == TRUE) {
1676                         switch (property->type) {
1677                         case DBUS_TYPE_STRING:
1678                                 *((char **) value) = property->value;
1679                                 found = TRUE;
1680                                 break;
1681                         }
1682                         break;
1683                 }
1684         }
1685
1686         __connman_element_unlock(element);
1687
1688         return found;
1689 }
1690
1691 gboolean connman_element_get_static_array_property(struct connman_element *element,
1692                                         const char *name, void *value, int *len)
1693 {
1694         GSList *list;
1695         gboolean found = FALSE;
1696
1697         DBG("element %p name %s", element, element->name);
1698
1699         __connman_element_lock(element);
1700
1701         for (list = element->properties; list; list = list->next) {
1702                 struct connman_property *property = list->data;
1703
1704                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1705                         continue;
1706
1707                 if (g_str_equal(property->name, name) == TRUE) {
1708                         *((char **) value) = property->value;
1709                         *len = property->size;
1710                         found = TRUE;
1711                         break;
1712                 }
1713         }
1714
1715         __connman_element_unlock(element);
1716
1717         return found;
1718 }
1719
1720 gboolean connman_element_match_static_property(struct connman_element *element,
1721                                         const char *name, const void *value)
1722 {
1723         GSList *list;
1724         gboolean result = FALSE;
1725
1726         DBG("element %p name %s", element, element->name);
1727
1728         __connman_element_lock(element);
1729
1730         for (list = element->properties; list; list = list->next) {
1731                 struct connman_property *property = list->data;
1732
1733                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1734                         continue;
1735
1736                 if (g_str_equal(property->name, name) == FALSE)
1737                         continue;
1738
1739                 if (property->type == DBUS_TYPE_STRING)
1740                         result = g_str_equal(property->value,
1741                                                 *((const char **) value));
1742
1743                 if (result == TRUE)
1744                         break;
1745         }
1746
1747         __connman_element_unlock(element);
1748
1749         return result;
1750 }
1751
1752 static void append_devices(DBusMessageIter *entry)
1753 {
1754         DBusMessageIter value, iter;
1755         const char *key = "Devices";
1756
1757         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1758
1759         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1760                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1761                                                                 &value);
1762
1763         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1764                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1765         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1766         dbus_message_iter_close_container(&value, &iter);
1767
1768         dbus_message_iter_close_container(entry, &value);
1769 }
1770
1771 static void emit_devices_signal(DBusConnection *conn)
1772 {
1773         DBusMessage *signal;
1774         DBusMessageIter entry;
1775
1776         DBG("conn %p", conn);
1777
1778         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1779                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1780         if (signal == NULL)
1781                 return;
1782
1783         dbus_message_iter_init_append(signal, &entry);
1784
1785         append_devices(&entry);
1786
1787         g_dbus_send_message(conn, signal);
1788 }
1789
1790 static void emit_networks_signal(DBusConnection *conn,
1791                                         struct connman_element *device)
1792 {
1793         DBusMessage *signal;
1794         DBusMessageIter entry;
1795
1796         DBG("conn %p", conn);
1797
1798         if (device == NULL)
1799                 return;
1800
1801         signal = dbus_message_new_signal(device->path,
1802                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1803         if (signal == NULL)
1804                 return;
1805
1806         dbus_message_iter_init_append(signal, &entry);
1807
1808         append_networks(device, &entry);
1809
1810         g_dbus_send_message(conn, signal);
1811 }
1812
1813 static void append_connections(DBusMessageIter *entry)
1814 {
1815         DBusMessageIter value, iter;
1816         const char *key = "Connections";
1817
1818         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1819
1820         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1821                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1822                                                                 &value);
1823
1824         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1825                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1826         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1827         dbus_message_iter_close_container(&value, &iter);
1828
1829         dbus_message_iter_close_container(entry, &value);
1830 }
1831
1832 static void emit_connections_signal(DBusConnection *conn)
1833 {
1834         DBusMessage *signal;
1835         DBusMessageIter entry;
1836
1837         DBG("conn %p", conn);
1838
1839         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1840                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1841         if (signal == NULL)
1842                 return;
1843
1844         dbus_message_iter_init_append(signal, &entry);
1845
1846         append_connections(&entry);
1847
1848         g_dbus_send_message(conn, signal);
1849 }
1850
1851 static void append_state(DBusMessageIter *entry, const char *state)
1852 {
1853         DBusMessageIter value;
1854         const char *key = "State";
1855
1856         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1857
1858         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1859                                         DBUS_TYPE_STRING_AS_STRING, &value);
1860         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1861         dbus_message_iter_close_container(entry, &value);
1862 }
1863
1864 static void emit_state_change(DBusConnection *conn, const char *state)
1865 {
1866         DBusMessage *signal;
1867         DBusMessageIter entry;
1868
1869         DBG("conn %p", conn);
1870
1871         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1872                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1873         if (signal == NULL)
1874                 return;
1875
1876         dbus_message_iter_init_append(signal, &entry);
1877
1878         append_state(&entry, state);
1879
1880         g_dbus_send_message(conn, signal);
1881 }
1882
1883 static void set_signal_strength(struct connman_element *connection)
1884 {
1885         struct connman_element *element = connection;
1886
1887         while (element != NULL) {
1888                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1889                         connection->strength = element->strength;
1890                         break;
1891                 }
1892
1893                 element = element->parent;
1894         }
1895 }
1896
1897 static void register_element(gpointer data, gpointer user_data)
1898 {
1899         struct connman_element *element = data;
1900         const gchar *basepath;
1901         GSList *list;
1902         GNode *node;
1903
1904         __connman_element_lock(element);
1905
1906         if (element->parent) {
1907                 node = g_node_find(element_root, G_PRE_ORDER,
1908                                         G_TRAVERSE_ALL, element->parent);
1909                 basepath = element->parent->path;
1910
1911                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1912                         element->subtype = element->parent->subtype;
1913         } else {
1914                 element->parent = element_root->data;
1915
1916                 node = element_root;
1917                 basepath = "";
1918         }
1919
1920         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1921
1922         set_reference_properties(element);
1923
1924         __connman_element_unlock(element);
1925
1926         DBG("element %p path %s", element, element->path);
1927
1928         __connman_element_load(element);
1929
1930         g_node_append_data(node, element);
1931
1932         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1933                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1934                 if (g_dbus_register_interface(connection, element->path,
1935                                         CONNMAN_DEVICE_INTERFACE,
1936                                         device_methods, element_signals,
1937                                         NULL, element, NULL) == FALSE)
1938                         connman_error("Failed to register %s device",
1939                                                                 element->path);
1940                 else
1941                         emit_devices_signal(connection);
1942         }
1943
1944         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1945                 if (g_dbus_register_interface(connection, element->path,
1946                                         CONNMAN_NETWORK_INTERFACE,
1947                                         network_methods, element_signals,
1948                                         NULL, element, NULL) == FALSE)
1949                         connman_error("Failed to register %s network",
1950                                                                 element->path);
1951                 else
1952                         emit_networks_signal(connection, element->parent);
1953         }
1954
1955         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1956                 if (g_dbus_register_interface(connection, element->path,
1957                                         CONNMAN_CONNECTION_INTERFACE,
1958                                         connection_methods, element_signals,
1959                                         NULL, element, NULL) == FALSE)
1960                         connman_error("Failed to register %s connection",
1961                                                                 element->path);
1962                 else {
1963                         set_signal_strength(element);
1964                         emit_connections_signal(connection);
1965                         emit_state_change(connection, "online");
1966                 }
1967         }
1968
1969         __connman_element_store(element);
1970
1971         for (list = driver_list; list; list = list->next) {
1972                 struct connman_driver *driver = list->data;
1973
1974                 if (match_driver(element, driver) == FALSE)
1975                         continue;
1976
1977                 DBG("driver %p name %s", driver, driver->name);
1978
1979                 if (driver->probe(element) == 0) {
1980                         __connman_element_lock(element);
1981                         element->driver = driver;
1982                         __connman_element_unlock(element);
1983
1984                         enable_element(element);
1985                         break;
1986                 }
1987         }
1988 }
1989
1990 /**
1991  * connman_element_register:
1992  * @element: the element to register
1993  * @parent: the parent to register the element with
1994  *
1995  * Register an element with the core. It will be register under the given
1996  * parent of if %NULL is provided under the root element.
1997  *
1998  * Returns: %0 on success
1999  */
2000 int connman_element_register(struct connman_element *element,
2001                                         struct connman_element *parent)
2002 {
2003         DBG("element %p name %s parent %p", element, element->name, parent);
2004
2005         if (element->devname == NULL)
2006                 element->devname = g_strdup(element->name);
2007
2008         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2009                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2010                 if (g_pattern_match_simple(device_filter,
2011                                                 element->devname) == FALSE) {
2012                         DBG("ignoring %s [%s] device", element->name,
2013                                                         element->devname);
2014                         return -EPERM;
2015                 }
2016         }
2017
2018         if (connman_element_ref(element) == NULL)
2019                 return -EINVAL;
2020
2021         __connman_element_lock(element);
2022
2023         if (element->name == NULL) {
2024                 element->name = g_strdup(type2string(element->type));
2025                 if (element->name == NULL) {
2026                         __connman_element_unlock(element);
2027                         return -EINVAL;
2028                 }
2029         }
2030
2031         element->parent = parent;
2032
2033         __connman_element_unlock(element);
2034
2035         register_element(element, NULL);
2036
2037         return 0;
2038 }
2039
2040 static gboolean remove_element(GNode *node, gpointer user_data)
2041 {
2042         struct connman_element *element = node->data;
2043         struct connman_element *root = user_data;
2044
2045         DBG("element %p name %s", element, element->name);
2046
2047         if (element == root)
2048                 return FALSE;
2049
2050         if (element->driver) {
2051                 disable_element(element);
2052
2053                 if (element->driver->remove)
2054                         element->driver->remove(element);
2055
2056                 __connman_element_lock(element);
2057                 element->driver = NULL;
2058                 __connman_element_unlock(element);
2059         }
2060
2061         if (node != NULL) {
2062                 g_node_unlink(node);
2063                 g_node_destroy(node);
2064         }
2065
2066         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
2067                 if (__connman_element_count(NULL,
2068                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
2069                         emit_state_change(connection, "offline");
2070                 emit_connections_signal(connection);
2071
2072                 g_dbus_unregister_interface(connection, element->path,
2073                                                 CONNMAN_CONNECTION_INTERFACE);
2074         }
2075
2076         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2077                 emit_networks_signal(connection, element->parent);
2078
2079                 g_dbus_unregister_interface(connection, element->path,
2080                                                 CONNMAN_NETWORK_INTERFACE);
2081         }
2082
2083         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2084                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2085                 emit_devices_signal(connection);
2086
2087                 g_dbus_unregister_interface(connection, element->path,
2088                                                 CONNMAN_DEVICE_INTERFACE);
2089         }
2090
2091         connman_element_unref(element);
2092
2093         return FALSE;
2094 }
2095
2096 void connman_element_unregister(struct connman_element *element)
2097 {
2098         GNode *node;
2099
2100         DBG("element %p name %s", element, element->name);
2101
2102         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2103
2104         if (node != NULL)
2105                 g_node_traverse(node, G_POST_ORDER,
2106                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
2107 }
2108
2109 void connman_element_unregister_children(struct connman_element *element)
2110 {
2111         GNode *node;
2112
2113         DBG("element %p name %s", element, element->name);
2114
2115         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2116
2117         if (node != NULL)
2118                 g_node_traverse(node, G_POST_ORDER,
2119                                 G_TRAVERSE_ALL, -1, remove_element, element);
2120 }
2121
2122 static gboolean update_element(GNode *node, gpointer user_data)
2123 {
2124         struct connman_element *element = node->data;
2125         struct connman_element *root = user_data;
2126
2127         DBG("element %p name %s", element, element->name);
2128
2129         if (element->driver && element->driver->update)
2130                 element->driver->update(element);
2131
2132         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION &&
2133                                 root->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2134                 if (element->strength != root->strength) {
2135                         element->strength = root->strength;
2136                         emit_property_changed(connection, element, "Strength",
2137                                         DBUS_TYPE_BYTE, &element->strength);
2138                 }
2139         }
2140
2141         return FALSE;
2142 }
2143
2144 void connman_element_update(struct connman_element *element)
2145 {
2146         GNode *node;
2147
2148         DBG("element %p name %s", element, element->name);
2149
2150         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2151
2152         if (node != NULL)
2153                 g_node_traverse(node, G_PRE_ORDER,
2154                                 G_TRAVERSE_ALL, -1, update_element, element);
2155 }
2156
2157 int connman_element_set_enabled(struct connman_element *element,
2158                                                         gboolean enabled)
2159 {
2160         if (element->enabled == enabled)
2161                 return 0;
2162
2163         element->enabled = enabled;
2164
2165         emit_enabled_signal(connection, element);
2166
2167         return 0;
2168 }
2169
2170 int connman_element_set_scanning(struct connman_element *element,
2171                                                         gboolean scanning)
2172 {
2173         if (element->scanning == scanning)
2174                 return 0;
2175
2176         element->scanning = scanning;
2177
2178         emit_scanning_signal(connection, element);
2179
2180         return 0;
2181 }
2182
2183 int __connman_element_init(DBusConnection *conn, const char *device)
2184 {
2185         struct connman_element *element;
2186
2187         DBG("conn %p", conn);
2188
2189         connection = dbus_connection_ref(conn);
2190         if (connection == NULL)
2191                 return -EIO;
2192
2193         device_filter = g_strdup(device);
2194
2195         element = connman_element_create("root");
2196
2197         element->path = g_strdup("/");
2198         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
2199
2200         create_default_properties(element);
2201
2202         element_root = g_node_new(element);
2203
2204         __connman_device_init();
2205
2206         return 0;
2207 }
2208
2209 static gboolean free_driver(GNode *node, gpointer data)
2210 {
2211         struct connman_element *element = node->data;
2212
2213         DBG("element %p name %s", element, element->name);
2214
2215         if (element->driver) {
2216                 disable_element(element);
2217
2218                 if (element->driver->remove)
2219                         element->driver->remove(element);
2220
2221                 __connman_element_lock(element);
2222                 element->driver = NULL;
2223                 __connman_element_unlock(element);
2224         }
2225
2226         return FALSE;
2227 }
2228
2229 static gboolean free_node(GNode *node, gpointer data)
2230 {
2231         struct connman_element *element = node->data;
2232
2233         DBG("element %p name %s", element, element->name);
2234
2235         if (g_node_depth(node) > 1)
2236                 connman_element_unregister(element);
2237
2238         return FALSE;
2239 }
2240
2241 void __connman_element_cleanup(void)
2242 {
2243         DBG("");
2244
2245         __connman_device_cleanup();
2246
2247         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2248                                                         free_driver, NULL);
2249
2250         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2251                                                         free_node, NULL);
2252
2253         g_node_destroy(element_root);
2254         element_root = NULL;
2255
2256         g_free(device_filter);
2257
2258         dbus_connection_unref(connection);
2259 }