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