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