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