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