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