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