Fix offline state signal emission
[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, element);
522                 else
523                         do_disable(conn, msg, element);
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 DBusMessage *connection_set_property(DBusConnection *conn,
730                                         DBusMessage *msg, void *data)
731 {
732         struct connman_element *element = data;
733         DBusMessageIter iter, value;
734         const char *name;
735
736         DBG("conn %p", conn);
737
738         if (dbus_message_iter_init(msg, &iter) == FALSE)
739                 return __connman_error_invalid_arguments(msg);
740
741         dbus_message_iter_get_basic(&iter, &name);
742         dbus_message_iter_next(&iter);
743         dbus_message_iter_recurse(&iter, &value);
744
745         if (__connman_security_check_privileges(msg) < 0)
746                 return __connman_error_permission_denied(msg);
747
748         if (g_str_equal(name, "Default") == TRUE) {
749                 dbus_bool_t enabled;
750
751                 dbus_message_iter_get_basic(&value, &enabled);
752
753                 if (enabled == TRUE)
754                         return do_enable(conn, msg, element);
755                 else
756                         return do_disable(conn, msg, element);
757         }
758
759         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
760 }
761
762 static GDBusMethodTable device_methods[] = {
763         { "GetProperties", "",      "a{sv}", device_get_properties },
764         { "SetProperty",   "sv",    "",      device_set_property   },
765         { "CreateNetwork", "a{sv}", "o",     device_create_network },
766         { "RemoveNetwork", "o",     "",      device_remove_network },
767         { "ProposeScan",   "",      "",      do_update             },
768         { },
769 };
770
771 static GDBusMethodTable network_methods[] = {
772         { "GetProperties", "",   "a{sv}", network_get_properties },
773         { "SetProperty",   "sv", "",      network_set_property   },
774         { "Connect",       "",   "",      do_enable              },
775         { "Disconnect",    "",   "",      do_disable             },
776         { },
777 };
778
779 static GDBusMethodTable connection_methods[] = {
780         { "GetProperties", "",   "a{sv}", connection_get_properties },
781         { "SetProperty",   "sv", "",      connection_set_property   },
782         { },
783 };
784
785 static GDBusSignalTable element_signals[] = {
786         { "PropertyChanged", "sv" },
787         { },
788 };
789
790 struct append_filter {
791         enum connman_element_type type;
792         DBusMessageIter *iter;
793 };
794
795 static gboolean append_path(GNode *node, gpointer user_data)
796 {
797         struct connman_element *element = node->data;
798         struct append_filter *filter = user_data;
799
800         DBG("element %p name %s", element, element->name);
801
802         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
803                 return FALSE;
804
805         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
806                                         filter->type != element->type)
807                 return FALSE;
808
809         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
810                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
811                 return FALSE;
812
813         dbus_message_iter_append_basic(filter->iter,
814                                 DBUS_TYPE_OBJECT_PATH, &element->path);
815
816         return FALSE;
817 }
818
819 void __connman_element_list(struct connman_element *element,
820                                         enum connman_element_type type,
821                                                         DBusMessageIter *iter)
822 {
823         struct append_filter filter = { type, iter };
824         GNode *node;
825
826         DBG("");
827
828         if (element != NULL) {
829                 node = g_node_find(element_root, G_PRE_ORDER,
830                                                 G_TRAVERSE_ALL, element);
831                 if (node == NULL)
832                         return;
833         } else
834                 node = element_root;
835
836         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
837                                                 append_path, &filter);
838 }
839
840 struct count_data {
841         enum connman_element_type type;
842         int count;
843 };
844
845 static gboolean count_element(GNode *node, gpointer user_data)
846 {
847         struct connman_element *element = node->data;
848         struct count_data *data = user_data;
849
850         DBG("element %p name %s", element, element->name);
851
852         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
853                 return FALSE;
854
855         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
856                                         data->type != element->type)
857                 return FALSE;
858
859         data->count++;
860
861         return FALSE;
862 }
863
864 int __connman_element_count(struct connman_element *element,
865                                         enum connman_element_type type)
866 {
867         struct count_data data = { type, 0 };
868         GNode *node;
869
870         DBG("");
871
872         if (element != NULL) {
873                 node = g_node_find(element_root, G_PRE_ORDER,
874                                                 G_TRAVERSE_ALL, element);
875                 if (node == NULL)
876                         return 0;
877         } else
878                 node = element_root;
879
880         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
881                                                 count_element, &data);
882
883         return data.count;
884 }
885
886 static gint compare_priority(gconstpointer a, gconstpointer b)
887 {
888         const struct connman_driver *driver1 = a;
889         const struct connman_driver *driver2 = b;
890
891         return driver2->priority - driver1->priority;
892 }
893
894 static gboolean match_driver(struct connman_element *element,
895                                         struct connman_driver *driver)
896 {
897         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
898                 return FALSE;
899
900         if (element->type != driver->type &&
901                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
902                 return FALSE;
903
904         if (element->subtype == driver->subtype ||
905                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
906                 return TRUE;
907
908         return FALSE;
909 }
910
911 static void enable_element(struct connman_element *element)
912 {
913         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
914                 return;
915
916         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
917                 return;
918
919         if (element->driver && element->driver->enable) {
920                 if (element->driver->enable(element) == 0) {
921                         element->enabled = TRUE;
922                         emit_enabled_signal(connection, element);
923                 }
924         }
925 }
926
927 static gboolean probe_driver(GNode *node, gpointer data)
928 {
929         struct connman_element *element = node->data;
930         struct connman_driver *driver = data;
931
932         DBG("element %p name %s", element, element->name);
933
934         if (!element->driver && match_driver(element, driver) == TRUE) {
935                 if (driver->probe(element) < 0)
936                         return FALSE;
937
938                 __connman_element_lock(element);
939                 element->driver = driver;
940                 __connman_element_unlock(element);
941
942                 enable_element(element);
943         }
944
945         return FALSE;
946 }
947
948 void __connman_driver_rescan(struct connman_driver *driver)
949 {
950         DBG("driver %p name %s", driver, driver->name);
951
952         if (!driver->probe)
953                 return;
954
955         if (element_root != NULL)
956                 g_node_traverse(element_root, G_PRE_ORDER,
957                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
958 }
959
960 /**
961  * connman_driver_register:
962  * @driver: driver definition
963  *
964  * Register a new driver
965  *
966  * Returns: %0 on success
967  */
968 int connman_driver_register(struct connman_driver *driver)
969 {
970         DBG("driver %p name %s", driver, driver->name);
971
972         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
973                 return -EINVAL;
974
975         if (!driver->probe)
976                 return -EINVAL;
977
978         driver_list = g_slist_insert_sorted(driver_list, driver,
979                                                         compare_priority);
980
981         if (element_root != NULL)
982                 g_node_traverse(element_root, G_PRE_ORDER,
983                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
984
985         return 0;
986 }
987
988 static void disable_element(struct connman_element *element)
989 {
990         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
991                 return;
992
993         if (element->enabled == FALSE)
994                 return;
995
996         if (element->driver && element->driver->disable) {
997                 if (element->driver->disable(element) == 0) {
998                         element->enabled = FALSE;
999                         emit_enabled_signal(connection, element);
1000                 }
1001         }
1002 }
1003
1004 static gboolean remove_driver(GNode *node, gpointer data)
1005 {
1006         struct connman_element *element = node->data;
1007         struct connman_driver *driver = data;
1008
1009         DBG("element %p name %s", element, element->name);
1010
1011         if (element->driver == driver) {
1012                 disable_element(element);
1013
1014                 if (driver->remove)
1015                         driver->remove(element);
1016
1017                 __connman_element_lock(element);
1018                 element->driver = NULL;
1019                 __connman_element_unlock(element);
1020         }
1021
1022         return FALSE;
1023 }
1024
1025 /**
1026  * connman_driver_unregister:
1027  * @driver: driver definition
1028  *
1029  * Remove a previously registered driver
1030  */
1031 void connman_driver_unregister(struct connman_driver *driver)
1032 {
1033         DBG("driver %p name %s", driver, driver->name);
1034
1035         driver_list = g_slist_remove(driver_list, driver);
1036
1037         if (element_root != NULL)
1038                 g_node_traverse(element_root, G_POST_ORDER,
1039                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
1040 }
1041
1042 /**
1043  * connman_element_create:
1044  * @name: element name
1045  *
1046  * Allocate a new element and assign the given #name to it. If the name
1047  * is #NULL, it will be later on created based on the element type.
1048  *
1049  * Returns: a newly-allocated #connman_element structure
1050  */
1051 struct connman_element *connman_element_create(const char *name)
1052 {
1053         struct connman_element *element;
1054
1055         element = g_try_new0(struct connman_element, 1);
1056         if (element == NULL)
1057                 return NULL;
1058
1059         DBG("element %p", element);
1060
1061         element->refcount = 1;
1062
1063         element->name    = g_strdup(name);
1064         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
1065         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
1066         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
1067         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
1068         element->index   = -1;
1069         element->enabled = FALSE;
1070
1071         return element;
1072 }
1073
1074 struct connman_element *connman_element_ref(struct connman_element *element)
1075 {
1076         DBG("element %p name %s refcount %d", element, element->name,
1077                                 g_atomic_int_get(&element->refcount) + 1);
1078
1079         g_atomic_int_inc(&element->refcount);
1080
1081         return element;
1082 }
1083
1084 static void free_properties(struct connman_element *element)
1085 {
1086         GSList *list;
1087
1088         DBG("element %p name %s", element, element->name);
1089
1090         __connman_element_lock(element);
1091
1092         for (list = element->properties; list; list = list->next) {
1093                 struct connman_property *property = list->data;
1094
1095                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1096                         g_free(property->value);
1097
1098                 g_free(property->name);
1099                 g_free(property);
1100         }
1101
1102         g_slist_free(element->properties);
1103
1104         element->properties = NULL;
1105
1106         __connman_element_unlock(element);
1107 }
1108
1109 void connman_element_unref(struct connman_element *element)
1110 {
1111         DBG("element %p name %s refcount %d", element, element->name,
1112                                 g_atomic_int_get(&element->refcount) - 1);
1113
1114         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
1115                 free_properties(element);
1116                 g_free(element->ipv4.address);
1117                 g_free(element->ipv4.netmask);
1118                 g_free(element->ipv4.gateway);
1119                 g_free(element->ipv4.network);
1120                 g_free(element->ipv4.broadcast);
1121                 g_free(element->ipv4.nameserver);
1122                 g_free(element->devname);
1123                 g_free(element->path);
1124                 g_free(element->name);
1125                 g_free(element);
1126         }
1127 }
1128
1129 int connman_element_add_static_property(struct connman_element *element,
1130                                 const char *name, int type, const void *value)
1131 {
1132         struct connman_property *property;
1133
1134         DBG("element %p name %s", element, element->name);
1135
1136         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1137                 return -EINVAL;
1138
1139         property = g_try_new0(struct connman_property, 1);
1140         if (property == NULL)
1141                 return -ENOMEM;
1142
1143         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
1144         property->id    = CONNMAN_PROPERTY_ID_INVALID;
1145         property->name  = g_strdup(name);
1146         property->type  = type;
1147
1148         DBG("name %s type %d value %p", name, type, value);
1149
1150         switch (type) {
1151         case DBUS_TYPE_STRING:
1152                 property->value = g_strdup(*((const char **) value));
1153                 break;
1154         case DBUS_TYPE_BYTE:
1155                 property->value = g_try_malloc(1);
1156                 if (property->value != NULL)
1157                         memcpy(property->value, value, 1);
1158                 break;
1159         }
1160
1161         __connman_element_lock(element);
1162         element->properties = g_slist_append(element->properties, property);
1163         __connman_element_unlock(element);
1164
1165         return 0;
1166 }
1167
1168 static void emit_property_changed(DBusConnection *conn,
1169                                 struct connman_element *element,
1170                                 const char *name, int type, const void *data)
1171 {
1172         DBusMessage *signal;
1173         DBusMessageIter entry, value;
1174         const char *iface, *sig;
1175
1176         DBG("conn %p", conn);
1177
1178         switch (element->type) {
1179         case CONNMAN_ELEMENT_TYPE_DEVICE:
1180                 iface = CONNMAN_DEVICE_INTERFACE;
1181                 break;
1182         case CONNMAN_ELEMENT_TYPE_NETWORK:
1183                 iface = CONNMAN_NETWORK_INTERFACE;
1184                 break;
1185         case CONNMAN_ELEMENT_TYPE_CONNECTION:
1186                 iface = CONNMAN_CONNECTION_INTERFACE;
1187                 break;
1188         default:
1189                 return;
1190         }
1191
1192         signal = dbus_message_new_signal(element->path,
1193                                                 iface, "PropertyChanged");
1194         if (signal == NULL)
1195                 return;
1196
1197         dbus_message_iter_init_append(signal, &entry);
1198
1199         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1200
1201         switch (type) {
1202         case DBUS_TYPE_STRING:
1203                 sig = DBUS_TYPE_STRING_AS_STRING;
1204                 break;
1205         case DBUS_TYPE_BYTE:
1206                 sig = DBUS_TYPE_BYTE_AS_STRING;
1207                 break;
1208         default:
1209                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1210                 break;
1211         }
1212
1213         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1214                                                         sig, &value);
1215         dbus_message_iter_append_basic(&value, type, data);
1216         dbus_message_iter_close_container(&entry, &value);
1217
1218         g_dbus_send_message(conn, signal);
1219 }
1220
1221 int connman_element_set_static_property(struct connman_element *element,
1222                                 const char *name, int type, const void *value)
1223 {
1224         GSList *list;
1225
1226         DBG("element %p name %s", element, element->name);
1227
1228         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1229                 return -EINVAL;
1230
1231         __connman_element_lock(element);
1232
1233         for (list = element->properties; list; list = list->next) {
1234                 struct connman_property *property = list->data;
1235
1236                 if (g_str_equal(property->name, name) == FALSE)
1237                         continue;
1238
1239                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1240                         continue;
1241
1242                 property->type = type;
1243                 g_free(property->value);
1244
1245                 switch (type) {
1246                 case DBUS_TYPE_STRING:
1247                         property->value = g_strdup(*((const char **) value));
1248                         break;
1249                 case DBUS_TYPE_BYTE:
1250                         property->value = g_try_malloc(1);
1251                         if (property->value != NULL)
1252                                 memcpy(property->value, value, 1);
1253                         break;
1254                 }
1255         }
1256
1257         __connman_element_unlock(element);
1258
1259         emit_property_changed(connection, element, name, type, value);
1260
1261         return 0;
1262 }
1263
1264 int connman_element_add_static_array_property(struct connman_element *element,
1265                         const char *name, int type, const void *value, int len)
1266 {
1267         struct connman_property *property;
1268
1269         DBG("element %p name %s", element, element->name);
1270
1271         if (type != DBUS_TYPE_BYTE)
1272                 return -EINVAL;
1273
1274         property = g_try_new0(struct connman_property, 1);
1275         if (property == NULL)
1276                 return -ENOMEM;
1277
1278         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1279         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1280         property->name    = g_strdup(name);
1281         property->type    = DBUS_TYPE_ARRAY;
1282         property->subtype = type;
1283
1284         DBG("name %s type %d value %p", name, type, value);
1285
1286         switch (type) {
1287         case DBUS_TYPE_BYTE:
1288                 property->value = g_try_malloc(len);
1289                 if (property->value != NULL) {
1290                         memcpy(property->value,
1291                                 *((const unsigned char **) value), len);
1292                         property->size = len;
1293                 }
1294                 break;
1295         }
1296
1297         __connman_element_lock(element);
1298         element->properties = g_slist_append(element->properties, property);
1299         __connman_element_unlock(element);
1300
1301         return 0;
1302 }
1303
1304 static void *get_reference_value(struct connman_element *element,
1305                                                 enum connman_property_id id)
1306 {
1307         GSList *list;
1308
1309         DBG("element %p name %s", element, element->name);
1310
1311         for (list = element->properties; list; list = list->next) {
1312                 struct connman_property *property = list->data;
1313
1314                 if (property->id != id)
1315                         continue;
1316
1317                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1318                         return property->value;
1319         }
1320
1321         if (element->parent == NULL)
1322                 return NULL;
1323
1324         return get_reference_value(element->parent, id);
1325 }
1326
1327 static void set_reference_properties(struct connman_element *element)
1328 {
1329         GSList *list;
1330
1331         DBG("element %p name %s", element, element->name);
1332
1333         for (list = element->properties; list; list = list->next) {
1334                 struct connman_property *property = list->data;
1335
1336                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1337                         continue;
1338
1339                 property->value = get_reference_value(element->parent,
1340                                                                 property->id);
1341         }
1342 }
1343
1344 static struct connman_property *create_property(struct connman_element *element,
1345                                                 enum connman_property_id id)
1346 {
1347         struct connman_property *property;
1348         GSList *list;
1349
1350         DBG("element %p name %s", element, element->name);
1351
1352         __connman_element_lock(element);
1353
1354         for (list = element->properties; list; list = list->next) {
1355                 property = list->data;
1356
1357                 if (property->id == id)
1358                         goto unlock;
1359         }
1360
1361         property = g_try_new0(struct connman_property, 1);
1362         if (property == NULL)
1363                 goto unlock;
1364
1365         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1366         property->id    = id;
1367         property->name  = g_strdup(propid2name(id));
1368         property->type  = propid2type(id);
1369
1370         if (property->name == NULL) {
1371                 g_free(property);
1372                 property = NULL;
1373                 goto unlock;
1374         }
1375
1376         element->properties = g_slist_append(element->properties, property);
1377
1378 unlock:
1379         __connman_element_unlock(element);
1380
1381         return property;
1382 }
1383
1384 static void create_default_properties(struct connman_element *element)
1385 {
1386         struct connman_property *property;
1387         int i;
1388
1389         DBG("element %p name %s", element, element->name);
1390
1391         for (i = 0; propid_table[i].name; i++) {
1392                 DBG("property %s", propid_table[i].name);
1393
1394                 property = create_property(element, propid_table[i].id);
1395
1396                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1397
1398                 if (propid_table[i].type != DBUS_TYPE_STRING)
1399                         continue;
1400
1401                 if (propid_table[i].value)
1402                         property->value = g_strdup(propid_table[i].value);
1403                 else
1404                         property->value = g_strdup("");
1405         }
1406 }
1407
1408 static int define_properties_valist(struct connman_element *element,
1409                                                                 va_list args)
1410 {
1411         enum connman_property_id id;
1412
1413         DBG("element %p name %s", element, element->name);
1414
1415         id = va_arg(args, enum connman_property_id);
1416
1417         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1418
1419                 DBG("property %d", id);
1420
1421                 create_property(element, id);
1422
1423                 id = va_arg(args, enum connman_property_id);
1424         }
1425
1426         return 0;
1427 }
1428
1429 /**
1430  * connman_element_define_properties:
1431  * @element: an element
1432  * @varargs: list of property identifiers
1433  *
1434  * Define the valid properties for an element.
1435  *
1436  * Returns: %0 on success
1437  */
1438 int connman_element_define_properties(struct connman_element *element, ...)
1439 {
1440         va_list args;
1441         int err;
1442
1443         DBG("element %p name %s", element, element->name);
1444
1445         va_start(args, element);
1446
1447         err = define_properties_valist(element, args);
1448
1449         va_end(args);
1450
1451         return err;
1452 }
1453
1454 int connman_element_create_property(struct connman_element *element,
1455                                                 const char *name, int type)
1456 {
1457         return -EIO;
1458 }
1459
1460 int connman_element_set_property(struct connman_element *element,
1461                                 enum connman_property_id id, const void *value)
1462 {
1463         switch (id) {
1464         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1465                 __connman_element_lock(element);
1466                 g_free(element->ipv4.address);
1467                 element->ipv4.address = g_strdup(*((const char **) value));
1468                 __connman_element_unlock(element);
1469                 break;
1470         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1471                 __connman_element_lock(element);
1472                 g_free(element->ipv4.netmask);
1473                 element->ipv4.netmask = g_strdup(*((const char **) value));
1474                 __connman_element_unlock(element);
1475                 break;
1476         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1477                 __connman_element_lock(element);
1478                 g_free(element->ipv4.gateway);
1479                 element->ipv4.gateway = g_strdup(*((const char **) value));
1480                 __connman_element_unlock(element);
1481                 break;
1482         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1483                 __connman_element_lock(element);
1484                 g_free(element->ipv4.broadcast);
1485                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1486                 __connman_element_unlock(element);
1487                 break;
1488         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1489                 __connman_element_lock(element);
1490                 g_free(element->ipv4.nameserver);
1491                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1492                 __connman_element_unlock(element);
1493                 break;
1494         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1495                 __connman_element_lock(element);
1496                 g_free(element->wifi.security);
1497                 element->wifi.security = g_strdup(*((const char **) value));
1498                 __connman_element_unlock(element);
1499                 break;
1500         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1501                 __connman_element_lock(element);
1502                 g_free(element->wifi.passphrase);
1503                 element->wifi.passphrase = g_strdup(*((const char **) value));
1504                 __connman_element_unlock(element);
1505                 break;
1506         default:
1507                 return -EINVAL;
1508         }
1509
1510         return 0;
1511 }
1512
1513 int connman_element_get_value(struct connman_element *element,
1514                                 enum connman_property_id id, void *value)
1515 {
1516         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1517                 return -EINVAL;
1518
1519         switch (id) {
1520         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1521                 if (element->ipv4.address == NULL)
1522                         return connman_element_get_value(element->parent,
1523                                                                 id, value);
1524                 __connman_element_lock(element);
1525                 *((char **) value) = element->ipv4.address;
1526                 __connman_element_unlock(element);
1527                 break;
1528         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1529                 if (element->ipv4.netmask == NULL)
1530                         return connman_element_get_value(element->parent,
1531                                                                 id, value);
1532                 __connman_element_lock(element);
1533                 *((char **) value) = element->ipv4.netmask;
1534                 __connman_element_unlock(element);
1535                 break;
1536         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1537                 if (element->ipv4.gateway == NULL)
1538                         return connman_element_get_value(element->parent,
1539                                                                 id, value);
1540                 __connman_element_lock(element);
1541                 *((char **) value) = element->ipv4.gateway;
1542                 __connman_element_unlock(element);
1543                 break;
1544         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1545                 if (element->ipv4.broadcast == NULL)
1546                         return connman_element_get_value(element->parent,
1547                                                                 id, value);
1548                 __connman_element_lock(element);
1549                 *((char **) value) = element->ipv4.broadcast;
1550                 __connman_element_unlock(element);
1551                 break;
1552         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1553                 if (element->ipv4.nameserver == NULL)
1554                         return connman_element_get_value(element->parent,
1555                                                                 id, value);
1556                 __connman_element_lock(element);
1557                 *((char **) value) = element->ipv4.nameserver;
1558                 __connman_element_unlock(element);
1559                 break;
1560         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1561                 if (element->wifi.security == NULL)
1562                         return connman_element_get_value(element->parent,
1563                                                                 id, value);
1564                 __connman_element_lock(element);
1565                 *((char **) value) = element->wifi.security;
1566                 __connman_element_unlock(element);
1567                 break;
1568         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1569                 if (element->wifi.passphrase == NULL)
1570                         return connman_element_get_value(element->parent,
1571                                                                 id, value);
1572                 __connman_element_lock(element);
1573                 *((char **) value) = element->wifi.passphrase;
1574                 __connman_element_unlock(element);
1575                 break;
1576         default:
1577                 return -EINVAL;
1578         }
1579
1580         return 0;
1581 }
1582
1583 gboolean connman_element_get_static_property(struct connman_element *element,
1584                                                 const char *name, void *value)
1585 {
1586         GSList *list;
1587         gboolean found = FALSE;
1588
1589         DBG("element %p name %s", element, element->name);
1590
1591         __connman_element_lock(element);
1592
1593         for (list = element->properties; list; list = list->next) {
1594                 struct connman_property *property = list->data;
1595
1596                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1597                         continue;
1598
1599                 if (g_str_equal(property->name, name) == TRUE) {
1600                         switch (property->type) {
1601                         case DBUS_TYPE_STRING:
1602                                 *((char **) value) = property->value;
1603                                 found = TRUE;
1604                                 break;
1605                         }
1606                         break;
1607                 }
1608         }
1609
1610         __connman_element_unlock(element);
1611
1612         return found;
1613 }
1614
1615 gboolean connman_element_get_static_array_property(struct connman_element *element,
1616                                         const char *name, void *value, int *len)
1617 {
1618         GSList *list;
1619         gboolean found = FALSE;
1620
1621         DBG("element %p name %s", element, element->name);
1622
1623         __connman_element_lock(element);
1624
1625         for (list = element->properties; list; list = list->next) {
1626                 struct connman_property *property = list->data;
1627
1628                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1629                         continue;
1630
1631                 if (g_str_equal(property->name, name) == TRUE) {
1632                         *((char **) value) = property->value;
1633                         *len = property->size;
1634                         found = TRUE;
1635                         break;
1636                 }
1637         }
1638
1639         __connman_element_unlock(element);
1640
1641         return found;
1642 }
1643
1644 gboolean connman_element_match_static_property(struct connman_element *element,
1645                                         const char *name, const void *value)
1646 {
1647         GSList *list;
1648         gboolean result = FALSE;
1649
1650         DBG("element %p name %s", element, element->name);
1651
1652         __connman_element_lock(element);
1653
1654         for (list = element->properties; list; list = list->next) {
1655                 struct connman_property *property = list->data;
1656
1657                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1658                         continue;
1659
1660                 if (g_str_equal(property->name, name) == FALSE)
1661                         continue;
1662
1663                 if (property->type == DBUS_TYPE_STRING)
1664                         result = g_str_equal(property->value,
1665                                                 *((const char **) value));
1666
1667                 if (result == TRUE)
1668                         break;
1669         }
1670
1671         __connman_element_unlock(element);
1672
1673         return result;
1674 }
1675
1676 static void append_devices(DBusMessageIter *entry)
1677 {
1678         DBusMessageIter value, iter;
1679         const char *key = "Devices";
1680
1681         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1682
1683         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1684                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1685                                                                 &value);
1686
1687         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1688                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1689         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1690         dbus_message_iter_close_container(&value, &iter);
1691
1692         dbus_message_iter_close_container(entry, &value);
1693 }
1694
1695 static void emit_devices_signal(DBusConnection *conn)
1696 {
1697         DBusMessage *signal;
1698         DBusMessageIter entry;
1699
1700         DBG("conn %p", conn);
1701
1702         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1703                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1704         if (signal == NULL)
1705                 return;
1706
1707         dbus_message_iter_init_append(signal, &entry);
1708
1709         append_devices(&entry);
1710
1711         g_dbus_send_message(conn, signal);
1712 }
1713
1714 static void emit_networks_signal(DBusConnection *conn,
1715                                         struct connman_element *device)
1716 {
1717         DBusMessage *signal;
1718         DBusMessageIter entry;
1719
1720         DBG("conn %p", conn);
1721
1722         if (device == NULL)
1723                 return;
1724
1725         signal = dbus_message_new_signal(device->path,
1726                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1727         if (signal == NULL)
1728                 return;
1729
1730         dbus_message_iter_init_append(signal, &entry);
1731
1732         append_networks(device, &entry);
1733
1734         g_dbus_send_message(conn, signal);
1735 }
1736
1737 static void append_connections(DBusMessageIter *entry)
1738 {
1739         DBusMessageIter value, iter;
1740         const char *key = "Connections";
1741
1742         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1743
1744         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1745                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1746                                                                 &value);
1747
1748         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1749                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1750         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1751         dbus_message_iter_close_container(&value, &iter);
1752
1753         dbus_message_iter_close_container(entry, &value);
1754 }
1755
1756 static void emit_connections_signal(DBusConnection *conn)
1757 {
1758         DBusMessage *signal;
1759         DBusMessageIter entry;
1760
1761         DBG("conn %p", conn);
1762
1763         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1764                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1765         if (signal == NULL)
1766                 return;
1767
1768         dbus_message_iter_init_append(signal, &entry);
1769
1770         append_connections(&entry);
1771
1772         g_dbus_send_message(conn, signal);
1773 }
1774
1775 static void append_state(DBusMessageIter *entry, const char *state)
1776 {
1777         DBusMessageIter value;
1778         const char *key = "State";
1779
1780         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1781
1782         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1783                                         DBUS_TYPE_STRING_AS_STRING, &value);
1784         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1785         dbus_message_iter_close_container(entry, &value);
1786 }
1787
1788 static void emit_state_change(DBusConnection *conn, const char *state)
1789 {
1790         DBusMessage *signal;
1791         DBusMessageIter entry;
1792
1793         DBG("conn %p", conn);
1794
1795         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1796                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1797         if (signal == NULL)
1798                 return;
1799
1800         dbus_message_iter_init_append(signal, &entry);
1801
1802         append_state(&entry, state);
1803
1804         g_dbus_send_message(conn, signal);
1805 }
1806
1807 static void set_signal_strength(struct connman_element *connection)
1808 {
1809         struct connman_element *element = connection;
1810
1811         while (element != NULL) {
1812                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1813                         connection->strength = element->strength;
1814                         break;
1815                 }
1816
1817                 element = element->parent;
1818         }
1819 }
1820
1821 static void register_element(gpointer data, gpointer user_data)
1822 {
1823         struct connman_element *element = data;
1824         const gchar *basepath;
1825         GSList *list;
1826         GNode *node;
1827
1828         __connman_element_lock(element);
1829
1830         if (element->parent) {
1831                 node = g_node_find(element_root, G_PRE_ORDER,
1832                                         G_TRAVERSE_ALL, element->parent);
1833                 basepath = element->parent->path;
1834
1835                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1836                         element->subtype = element->parent->subtype;
1837         } else {
1838                 element->parent = element_root->data;
1839
1840                 node = element_root;
1841                 basepath = "";
1842         }
1843
1844         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1845
1846         set_reference_properties(element);
1847
1848         __connman_element_unlock(element);
1849
1850         DBG("element %p path %s", element, element->path);
1851
1852         __connman_element_load(element);
1853
1854         g_node_append_data(node, element);
1855
1856         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1857                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1858                 if (g_dbus_register_interface(connection, element->path,
1859                                         CONNMAN_DEVICE_INTERFACE,
1860                                         device_methods, element_signals,
1861                                         NULL, element, NULL) == FALSE)
1862                         connman_error("Failed to register %s device",
1863                                                                 element->path);
1864                 else
1865                         emit_devices_signal(connection);
1866         }
1867
1868         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1869                 if (g_dbus_register_interface(connection, element->path,
1870                                         CONNMAN_NETWORK_INTERFACE,
1871                                         network_methods, element_signals,
1872                                         NULL, element, NULL) == FALSE)
1873                         connman_error("Failed to register %s network",
1874                                                                 element->path);
1875                 else
1876                         emit_networks_signal(connection, element->parent);
1877         }
1878
1879         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1880                 if (g_dbus_register_interface(connection, element->path,
1881                                         CONNMAN_CONNECTION_INTERFACE,
1882                                         connection_methods, element_signals,
1883                                         NULL, element, NULL) == FALSE)
1884                         connman_error("Failed to register %s connection",
1885                                                                 element->path);
1886                 else {
1887                         set_signal_strength(element);
1888                         emit_connections_signal(connection);
1889                         emit_state_change(connection, "online");
1890                 }
1891         }
1892
1893         __connman_element_store(element);
1894
1895         for (list = driver_list; list; list = list->next) {
1896                 struct connman_driver *driver = list->data;
1897
1898                 if (match_driver(element, driver) == FALSE)
1899                         continue;
1900
1901                 DBG("driver %p name %s", driver, driver->name);
1902
1903                 if (driver->probe(element) == 0) {
1904                         __connman_element_lock(element);
1905                         element->driver = driver;
1906                         __connman_element_unlock(element);
1907
1908                         enable_element(element);
1909                         break;
1910                 }
1911         }
1912 }
1913
1914 /**
1915  * connman_element_register:
1916  * @element: the element to register
1917  * @parent: the parent to register the element with
1918  *
1919  * Register an element with the core. It will be register under the given
1920  * parent of if %NULL is provided under the root element.
1921  *
1922  * Returns: %0 on success
1923  */
1924 int connman_element_register(struct connman_element *element,
1925                                         struct connman_element *parent)
1926 {
1927         DBG("element %p name %s parent %p", element, element->name, parent);
1928
1929         if (element->devname == NULL)
1930                 element->devname = g_strdup(element->name);
1931
1932         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1933                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1934                 if (g_pattern_match_simple(device_filter,
1935                                                 element->devname) == FALSE) {
1936                         DBG("ignoring %s [%s] device", element->name,
1937                                                         element->devname);
1938                         return -EPERM;
1939                 }
1940         }
1941
1942         if (connman_element_ref(element) == NULL)
1943                 return -EINVAL;
1944
1945         __connman_element_lock(element);
1946
1947         if (element->name == NULL) {
1948                 element->name = g_strdup(type2string(element->type));
1949                 if (element->name == NULL) {
1950                         __connman_element_unlock(element);
1951                         return -EINVAL;
1952                 }
1953         }
1954
1955         element->parent = parent;
1956
1957         __connman_element_unlock(element);
1958
1959         register_element(element, NULL);
1960
1961         return 0;
1962 }
1963
1964 static gboolean remove_element(GNode *node, gpointer user_data)
1965 {
1966         struct connman_element *element = node->data;
1967         struct connman_element *root = user_data;
1968
1969         DBG("element %p name %s", element, element->name);
1970
1971         if (element == root)
1972                 return FALSE;
1973
1974         if (element->driver) {
1975                 disable_element(element);
1976
1977                 if (element->driver->remove)
1978                         element->driver->remove(element);
1979
1980                 __connman_element_lock(element);
1981                 element->driver = NULL;
1982                 __connman_element_unlock(element);
1983         }
1984
1985         if (node != NULL) {
1986                 g_node_unlink(node);
1987                 g_node_destroy(node);
1988         }
1989
1990         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1991                 if (__connman_element_count(NULL,
1992                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1993                         emit_state_change(connection, "offline");
1994                 emit_connections_signal(connection);
1995
1996                 g_dbus_unregister_interface(connection, element->path,
1997                                                 CONNMAN_CONNECTION_INTERFACE);
1998         }
1999
2000         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2001                 emit_networks_signal(connection, element->parent);
2002
2003                 g_dbus_unregister_interface(connection, element->path,
2004                                                 CONNMAN_NETWORK_INTERFACE);
2005         }
2006
2007         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2008                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2009                 emit_devices_signal(connection);
2010
2011                 g_dbus_unregister_interface(connection, element->path,
2012                                                 CONNMAN_DEVICE_INTERFACE);
2013         }
2014
2015         connman_element_unref(element);
2016
2017         return FALSE;
2018 }
2019
2020 void connman_element_unregister(struct connman_element *element)
2021 {
2022         GNode *node;
2023
2024         DBG("element %p name %s", element, element->name);
2025
2026         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2027
2028         if (node != NULL)
2029                 g_node_traverse(node, G_POST_ORDER,
2030                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
2031 }
2032
2033 void connman_element_unregister_children(struct connman_element *element)
2034 {
2035         GNode *node;
2036
2037         DBG("element %p name %s", element, element->name);
2038
2039         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2040
2041         if (node != NULL)
2042                 g_node_traverse(node, G_POST_ORDER,
2043                                 G_TRAVERSE_ALL, -1, remove_element, element);
2044 }
2045
2046 static gboolean update_element(GNode *node, gpointer user_data)
2047 {
2048         struct connman_element *element = node->data;
2049         struct connman_element *root = user_data;
2050
2051         DBG("element %p name %s", element, element->name);
2052
2053         if (element->driver && element->driver->update)
2054                 element->driver->update(element);
2055
2056         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION &&
2057                                 root->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2058                 if (element->strength != root->strength) {
2059                         element->strength = root->strength;
2060                         emit_property_changed(connection, element, "Strength",
2061                                         DBUS_TYPE_BYTE, &element->strength);
2062                 }
2063         }
2064
2065         return FALSE;
2066 }
2067
2068 void connman_element_update(struct connman_element *element)
2069 {
2070         GNode *node;
2071
2072         DBG("element %p name %s", element, element->name);
2073
2074         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2075
2076         if (node != NULL)
2077                 g_node_traverse(node, G_PRE_ORDER,
2078                                 G_TRAVERSE_ALL, -1, update_element, element);
2079 }
2080
2081 int connman_element_set_enabled(struct connman_element *element,
2082                                                         gboolean enabled)
2083 {
2084         if (element->enabled == enabled)
2085                 return 0;
2086
2087         element->enabled = enabled;
2088
2089         emit_enabled_signal(connection, element);
2090
2091         return 0;
2092 }
2093
2094 int __connman_element_init(DBusConnection *conn, const char *device)
2095 {
2096         struct connman_element *element;
2097
2098         DBG("conn %p", conn);
2099
2100         connection = dbus_connection_ref(conn);
2101         if (connection == NULL)
2102                 return -EIO;
2103
2104         device_filter = g_strdup(device);
2105
2106         element = connman_element_create("root");
2107
2108         element->path = g_strdup("/");
2109         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
2110
2111         create_default_properties(element);
2112
2113         element_root = g_node_new(element);
2114
2115         __connman_device_init();
2116
2117         return 0;
2118 }
2119
2120 static gboolean free_driver(GNode *node, gpointer data)
2121 {
2122         struct connman_element *element = node->data;
2123
2124         DBG("element %p name %s", element, element->name);
2125
2126         if (element->driver) {
2127                 disable_element(element);
2128
2129                 if (element->driver->remove)
2130                         element->driver->remove(element);
2131
2132                 __connman_element_lock(element);
2133                 element->driver = NULL;
2134                 __connman_element_unlock(element);
2135         }
2136
2137         return FALSE;
2138 }
2139
2140 static gboolean free_node(GNode *node, gpointer data)
2141 {
2142         struct connman_element *element = node->data;
2143
2144         DBG("element %p name %s", element, element->name);
2145
2146         if (g_node_depth(node) > 1)
2147                 connman_element_unregister(element);
2148
2149         return FALSE;
2150 }
2151
2152 void __connman_element_cleanup(void)
2153 {
2154         DBG("");
2155
2156         __connman_device_cleanup();
2157
2158         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2159                                                         free_driver, NULL);
2160
2161         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2162                                                         free_node, NULL);
2163
2164         g_node_destroy(element_root);
2165         element_root = NULL;
2166
2167         g_free(device_filter);
2168
2169         dbus_connection_unref(connection);
2170 }