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