Add signal strength to connection objects
[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         default:
1143                 return;
1144         }
1145
1146         signal = dbus_message_new_signal(element->path,
1147                                                 iface, "PropertyChanged");
1148         if (signal == NULL)
1149                 return;
1150
1151         dbus_message_iter_init_append(signal, &entry);
1152
1153         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1154
1155         switch (type) {
1156         case DBUS_TYPE_STRING:
1157                 sig = DBUS_TYPE_STRING_AS_STRING;
1158                 break;
1159         case DBUS_TYPE_BYTE:
1160                 sig = DBUS_TYPE_BYTE_AS_STRING;
1161                 break;
1162         default:
1163                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1164                 break;
1165         }
1166
1167         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1168                                                         sig, &value);
1169         dbus_message_iter_append_basic(&value, type, data);
1170         dbus_message_iter_close_container(&entry, &value);
1171
1172         g_dbus_send_message(conn, signal);
1173 }
1174
1175 int connman_element_set_static_property(struct connman_element *element,
1176                                 const char *name, int type, const void *value)
1177 {
1178         GSList *list;
1179
1180         DBG("element %p name %s", element, element->name);
1181
1182         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1183                 return -EINVAL;
1184
1185         __connman_element_lock(element);
1186
1187         for (list = element->properties; list; list = list->next) {
1188                 struct connman_property *property = list->data;
1189
1190                 if (g_str_equal(property->name, name) == FALSE)
1191                         continue;
1192
1193                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1194                         continue;
1195
1196                 property->type = type;
1197                 g_free(property->value);
1198
1199                 switch (type) {
1200                 case DBUS_TYPE_STRING:
1201                         property->value = g_strdup(*((const char **) value));
1202                         break;
1203                 case DBUS_TYPE_BYTE:
1204                         property->value = g_try_malloc(1);
1205                         if (property->value != NULL)
1206                                 memcpy(property->value, value, 1);
1207                         break;
1208                 }
1209         }
1210
1211         __connman_element_unlock(element);
1212
1213         emit_property_changed(connection, element, name, type, value);
1214
1215         return 0;
1216 }
1217
1218 int connman_element_add_static_array_property(struct connman_element *element,
1219                         const char *name, int type, const void *value, int len)
1220 {
1221         struct connman_property *property;
1222
1223         DBG("element %p name %s", element, element->name);
1224
1225         if (type != DBUS_TYPE_BYTE)
1226                 return -EINVAL;
1227
1228         property = g_try_new0(struct connman_property, 1);
1229         if (property == NULL)
1230                 return -ENOMEM;
1231
1232         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1233         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1234         property->name    = g_strdup(name);
1235         property->type    = DBUS_TYPE_ARRAY;
1236         property->subtype = type;
1237
1238         DBG("name %s type %d value %p", name, type, value);
1239
1240         switch (type) {
1241         case DBUS_TYPE_BYTE:
1242                 property->value = g_try_malloc(len);
1243                 if (property->value != NULL) {
1244                         memcpy(property->value,
1245                                 *((const unsigned char **) value), len);
1246                         property->size = len;
1247                 }
1248                 break;
1249         }
1250
1251         __connman_element_lock(element);
1252         element->properties = g_slist_append(element->properties, property);
1253         __connman_element_unlock(element);
1254
1255         return 0;
1256 }
1257
1258 static void *get_reference_value(struct connman_element *element,
1259                                                 enum connman_property_id id)
1260 {
1261         GSList *list;
1262
1263         DBG("element %p name %s", element, element->name);
1264
1265         for (list = element->properties; list; list = list->next) {
1266                 struct connman_property *property = list->data;
1267
1268                 if (property->id != id)
1269                         continue;
1270
1271                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1272                         return property->value;
1273         }
1274
1275         if (element->parent == NULL)
1276                 return NULL;
1277
1278         return get_reference_value(element->parent, id);
1279 }
1280
1281 static void set_reference_properties(struct connman_element *element)
1282 {
1283         GSList *list;
1284
1285         DBG("element %p name %s", element, element->name);
1286
1287         for (list = element->properties; list; list = list->next) {
1288                 struct connman_property *property = list->data;
1289
1290                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1291                         continue;
1292
1293                 property->value = get_reference_value(element->parent,
1294                                                                 property->id);
1295         }
1296 }
1297
1298 static struct connman_property *create_property(struct connman_element *element,
1299                                                 enum connman_property_id id)
1300 {
1301         struct connman_property *property;
1302         GSList *list;
1303
1304         DBG("element %p name %s", element, element->name);
1305
1306         __connman_element_lock(element);
1307
1308         for (list = element->properties; list; list = list->next) {
1309                 property = list->data;
1310
1311                 if (property->id == id)
1312                         goto unlock;
1313         }
1314
1315         property = g_try_new0(struct connman_property, 1);
1316         if (property == NULL)
1317                 goto unlock;
1318
1319         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1320         property->id    = id;
1321         property->name  = g_strdup(propid2name(id));
1322         property->type  = propid2type(id);
1323
1324         if (property->name == NULL) {
1325                 g_free(property);
1326                 property = NULL;
1327                 goto unlock;
1328         }
1329
1330         element->properties = g_slist_append(element->properties, property);
1331
1332 unlock:
1333         __connman_element_unlock(element);
1334
1335         return property;
1336 }
1337
1338 static void create_default_properties(struct connman_element *element)
1339 {
1340         struct connman_property *property;
1341         int i;
1342
1343         DBG("element %p name %s", element, element->name);
1344
1345         for (i = 0; propid_table[i].name; i++) {
1346                 DBG("property %s", propid_table[i].name);
1347
1348                 property = create_property(element, propid_table[i].id);
1349
1350                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1351
1352                 if (propid_table[i].type != DBUS_TYPE_STRING)
1353                         continue;
1354
1355                 if (propid_table[i].value)
1356                         property->value = g_strdup(propid_table[i].value);
1357                 else
1358                         property->value = g_strdup("");
1359         }
1360 }
1361
1362 static int define_properties_valist(struct connman_element *element,
1363                                                                 va_list args)
1364 {
1365         enum connman_property_id id;
1366
1367         DBG("element %p name %s", element, element->name);
1368
1369         id = va_arg(args, enum connman_property_id);
1370
1371         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1372
1373                 DBG("property %d", id);
1374
1375                 create_property(element, id);
1376
1377                 id = va_arg(args, enum connman_property_id);
1378         }
1379
1380         return 0;
1381 }
1382
1383 /**
1384  * connman_element_define_properties:
1385  * @element: an element
1386  * @varargs: list of property identifiers
1387  *
1388  * Define the valid properties for an element.
1389  *
1390  * Returns: %0 on success
1391  */
1392 int connman_element_define_properties(struct connman_element *element, ...)
1393 {
1394         va_list args;
1395         int err;
1396
1397         DBG("element %p name %s", element, element->name);
1398
1399         va_start(args, element);
1400
1401         err = define_properties_valist(element, args);
1402
1403         va_end(args);
1404
1405         return err;
1406 }
1407
1408 int connman_element_create_property(struct connman_element *element,
1409                                                 const char *name, int type)
1410 {
1411         return -EIO;
1412 }
1413
1414 int connman_element_set_property(struct connman_element *element,
1415                                 enum connman_property_id id, const void *value)
1416 {
1417         switch (id) {
1418         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1419                 __connman_element_lock(element);
1420                 g_free(element->ipv4.address);
1421                 element->ipv4.address = g_strdup(*((const char **) value));
1422                 __connman_element_unlock(element);
1423                 break;
1424         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1425                 __connman_element_lock(element);
1426                 g_free(element->ipv4.netmask);
1427                 element->ipv4.netmask = g_strdup(*((const char **) value));
1428                 __connman_element_unlock(element);
1429                 break;
1430         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1431                 __connman_element_lock(element);
1432                 g_free(element->ipv4.gateway);
1433                 element->ipv4.gateway = g_strdup(*((const char **) value));
1434                 __connman_element_unlock(element);
1435                 break;
1436         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1437                 __connman_element_lock(element);
1438                 g_free(element->ipv4.nameserver);
1439                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1440                 __connman_element_unlock(element);
1441                 break;
1442         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1443                 __connman_element_lock(element);
1444                 g_free(element->wifi.security);
1445                 element->wifi.security = g_strdup(*((const char **) value));
1446                 __connman_element_unlock(element);
1447                 break;
1448         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1449                 __connman_element_lock(element);
1450                 g_free(element->wifi.passphrase);
1451                 element->wifi.passphrase = g_strdup(*((const char **) value));
1452                 __connman_element_unlock(element);
1453                 break;
1454         default:
1455                 return -EINVAL;
1456         }
1457
1458         return 0;
1459 }
1460
1461 int connman_element_get_value(struct connman_element *element,
1462                                 enum connman_property_id id, void *value)
1463 {
1464         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1465                 return -EINVAL;
1466
1467         switch (id) {
1468         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1469                 if (element->ipv4.address == NULL)
1470                         return connman_element_get_value(element->parent,
1471                                                                 id, value);
1472                 __connman_element_lock(element);
1473                 *((char **) value) = element->ipv4.address;
1474                 __connman_element_unlock(element);
1475                 break;
1476         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1477                 if (element->ipv4.netmask == NULL)
1478                         return connman_element_get_value(element->parent,
1479                                                                 id, value);
1480                 __connman_element_lock(element);
1481                 *((char **) value) = element->ipv4.netmask;
1482                 __connman_element_unlock(element);
1483                 break;
1484         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1485                 if (element->ipv4.gateway == NULL)
1486                         return connman_element_get_value(element->parent,
1487                                                                 id, value);
1488                 __connman_element_lock(element);
1489                 *((char **) value) = element->ipv4.gateway;
1490                 __connman_element_unlock(element);
1491                 break;
1492         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1493                 if (element->ipv4.nameserver == NULL)
1494                         return connman_element_get_value(element->parent,
1495                                                                 id, value);
1496                 __connman_element_lock(element);
1497                 *((char **) value) = element->ipv4.nameserver;
1498                 __connman_element_unlock(element);
1499                 break;
1500         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1501                 if (element->wifi.security == NULL)
1502                         return connman_element_get_value(element->parent,
1503                                                                 id, value);
1504                 __connman_element_lock(element);
1505                 *((char **) value) = element->wifi.security;
1506                 __connman_element_unlock(element);
1507                 break;
1508         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1509                 if (element->wifi.passphrase == NULL)
1510                         return connman_element_get_value(element->parent,
1511                                                                 id, value);
1512                 __connman_element_lock(element);
1513                 *((char **) value) = element->wifi.passphrase;
1514                 __connman_element_unlock(element);
1515                 break;
1516         default:
1517                 return -EINVAL;
1518         }
1519
1520         return 0;
1521 }
1522
1523 gboolean connman_element_get_static_property(struct connman_element *element,
1524                                                 const char *name, void *value)
1525 {
1526         GSList *list;
1527         gboolean found = FALSE;
1528
1529         DBG("element %p name %s", element, element->name);
1530
1531         __connman_element_lock(element);
1532
1533         for (list = element->properties; list; list = list->next) {
1534                 struct connman_property *property = list->data;
1535
1536                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1537                         continue;
1538
1539                 if (g_str_equal(property->name, name) == TRUE) {
1540                         switch (property->type) {
1541                         case DBUS_TYPE_STRING:
1542                                 *((char **) value) = property->value;
1543                                 found = TRUE;
1544                                 break;
1545                         }
1546                         break;
1547                 }
1548         }
1549
1550         __connman_element_unlock(element);
1551
1552         return found;
1553 }
1554
1555 gboolean connman_element_get_static_array_property(struct connman_element *element,
1556                                         const char *name, void *value, int *len)
1557 {
1558         GSList *list;
1559         gboolean found = FALSE;
1560
1561         DBG("element %p name %s", element, element->name);
1562
1563         __connman_element_lock(element);
1564
1565         for (list = element->properties; list; list = list->next) {
1566                 struct connman_property *property = list->data;
1567
1568                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1569                         continue;
1570
1571                 if (g_str_equal(property->name, name) == TRUE) {
1572                         *((char **) value) = property->value;
1573                         *len = property->size;
1574                         found = TRUE;
1575                         break;
1576                 }
1577         }
1578
1579         __connman_element_unlock(element);
1580
1581         return found;
1582 }
1583
1584 gboolean connman_element_match_static_property(struct connman_element *element,
1585                                         const char *name, const void *value)
1586 {
1587         GSList *list;
1588         gboolean result = FALSE;
1589
1590         DBG("element %p name %s", element, element->name);
1591
1592         __connman_element_lock(element);
1593
1594         for (list = element->properties; list; list = list->next) {
1595                 struct connman_property *property = list->data;
1596
1597                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1598                         continue;
1599
1600                 if (g_str_equal(property->name, name) == FALSE)
1601                         continue;
1602
1603                 if (property->type == DBUS_TYPE_STRING)
1604                         result = g_str_equal(property->value,
1605                                                 *((const char **) value));
1606
1607                 if (result == TRUE)
1608                         break;
1609         }
1610
1611         __connman_element_unlock(element);
1612
1613         return result;
1614 }
1615
1616 static void append_devices(DBusMessageIter *entry)
1617 {
1618         DBusMessageIter value, iter;
1619         const char *key = "Devices";
1620
1621         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1622
1623         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1624                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1625                                                                 &value);
1626
1627         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1628                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1629         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1630         dbus_message_iter_close_container(&value, &iter);
1631
1632         dbus_message_iter_close_container(entry, &value);
1633 }
1634
1635 static void emit_devices_signal(DBusConnection *conn)
1636 {
1637         DBusMessage *signal;
1638         DBusMessageIter entry;
1639
1640         DBG("conn %p", conn);
1641
1642         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1643                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1644         if (signal == NULL)
1645                 return;
1646
1647         dbus_message_iter_init_append(signal, &entry);
1648
1649         append_devices(&entry);
1650
1651         g_dbus_send_message(conn, signal);
1652 }
1653
1654 static void emit_networks_signal(DBusConnection *conn,
1655                                         struct connman_element *device)
1656 {
1657         DBusMessage *signal;
1658         DBusMessageIter entry;
1659
1660         DBG("conn %p", conn);
1661
1662         if (device == NULL)
1663                 return;
1664
1665         signal = dbus_message_new_signal(device->path,
1666                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1667         if (signal == NULL)
1668                 return;
1669
1670         dbus_message_iter_init_append(signal, &entry);
1671
1672         append_networks(device, &entry);
1673
1674         g_dbus_send_message(conn, signal);
1675 }
1676
1677 static void append_connections(DBusMessageIter *entry)
1678 {
1679         DBusMessageIter value, iter;
1680         const char *key = "Connections";
1681
1682         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1683
1684         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1685                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1686                                                                 &value);
1687
1688         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1689                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1690         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1691         dbus_message_iter_close_container(&value, &iter);
1692
1693         dbus_message_iter_close_container(entry, &value);
1694 }
1695
1696 static void emit_connections_signal(DBusConnection *conn)
1697 {
1698         DBusMessage *signal;
1699         DBusMessageIter entry;
1700
1701         DBG("conn %p", conn);
1702
1703         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1704                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1705         if (signal == NULL)
1706                 return;
1707
1708         dbus_message_iter_init_append(signal, &entry);
1709
1710         append_connections(&entry);
1711
1712         g_dbus_send_message(conn, signal);
1713 }
1714
1715 static void append_state(DBusMessageIter *entry, const char *state)
1716 {
1717         DBusMessageIter value;
1718         const char *key = "State";
1719
1720         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1721
1722         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1723                                         DBUS_TYPE_STRING_AS_STRING, &value);
1724         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1725         dbus_message_iter_close_container(entry, &value);
1726 }
1727
1728 static void emit_state_change(DBusConnection *conn, const char *state)
1729 {
1730         DBusMessage *signal;
1731         DBusMessageIter entry;
1732
1733         DBG("conn %p", conn);
1734
1735         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1736                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1737         if (signal == NULL)
1738                 return;
1739
1740         dbus_message_iter_init_append(signal, &entry);
1741
1742         append_state(&entry, state);
1743
1744         g_dbus_send_message(conn, signal);
1745 }
1746
1747 static void set_signal_strength(struct connman_element *connection)
1748 {
1749         struct connman_element *element = connection;
1750
1751         while (element != NULL) {
1752                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1753                         connection->strength = element->strength;
1754                         break;
1755                 }
1756
1757                 element = element->parent;
1758         }
1759 }
1760
1761 static void register_element(gpointer data, gpointer user_data)
1762 {
1763         struct connman_element *element = data;
1764         const gchar *basepath;
1765         GSList *list;
1766         GNode *node;
1767
1768         __connman_element_lock(element);
1769
1770         if (element->parent) {
1771                 node = g_node_find(element_root, G_PRE_ORDER,
1772                                         G_TRAVERSE_ALL, element->parent);
1773                 basepath = element->parent->path;
1774
1775                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1776                         element->subtype = element->parent->subtype;
1777         } else {
1778                 element->parent = element_root->data;
1779
1780                 node = element_root;
1781                 basepath = "";
1782         }
1783
1784         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1785
1786         set_reference_properties(element);
1787
1788         __connman_element_unlock(element);
1789
1790         DBG("element %p path %s", element, element->path);
1791
1792         __connman_element_load(element);
1793
1794         g_node_append_data(node, element);
1795
1796         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1797                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1798                 if (g_dbus_register_interface(connection, element->path,
1799                                         CONNMAN_DEVICE_INTERFACE,
1800                                         device_methods, element_signals,
1801                                         NULL, element, NULL) == FALSE)
1802                         connman_error("Failed to register %s device",
1803                                                                 element->path);
1804                 else
1805                         emit_devices_signal(connection);
1806         }
1807
1808         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1809                 if (g_dbus_register_interface(connection, element->path,
1810                                         CONNMAN_NETWORK_INTERFACE,
1811                                         network_methods, element_signals,
1812                                         NULL, element, NULL) == FALSE)
1813                         connman_error("Failed to register %s network",
1814                                                                 element->path);
1815                 else
1816                         emit_networks_signal(connection, element->parent);
1817         }
1818
1819         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1820                 if (g_dbus_register_interface(connection, element->path,
1821                                         CONNMAN_CONNECTION_INTERFACE,
1822                                         connection_methods, element_signals,
1823                                         NULL, element, NULL) == FALSE)
1824                         connman_error("Failed to register %s connection",
1825                                                                 element->path);
1826                 else {
1827                         set_signal_strength(element);
1828                         emit_connections_signal(connection);
1829                         emit_state_change(connection, "online");
1830                 }
1831         }
1832
1833         __connman_element_store(element);
1834
1835         for (list = driver_list; list; list = list->next) {
1836                 struct connman_driver *driver = list->data;
1837
1838                 if (match_driver(element, driver) == FALSE)
1839                         continue;
1840
1841                 DBG("driver %p name %s", driver, driver->name);
1842
1843                 if (driver->probe(element) == 0) {
1844                         __connman_element_lock(element);
1845                         element->driver = driver;
1846                         __connman_element_unlock(element);
1847
1848                         enable_element(element);
1849                         break;
1850                 }
1851         }
1852 }
1853
1854 /**
1855  * connman_element_register:
1856  * @element: the element to register
1857  * @parent: the parent to register the element with
1858  *
1859  * Register an element with the core. It will be register under the given
1860  * parent of if %NULL is provided under the root element.
1861  *
1862  * Returns: %0 on success
1863  */
1864 int connman_element_register(struct connman_element *element,
1865                                         struct connman_element *parent)
1866 {
1867         DBG("element %p name %s parent %p", element, element->name, parent);
1868
1869         if (element->devname == NULL)
1870                 element->devname = g_strdup(element->name);
1871
1872         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1873                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1874                 if (g_pattern_match_simple(device_filter,
1875                                                 element->devname) == FALSE) {
1876                         DBG("ignoring %s [%s] device", element->name,
1877                                                         element->devname);
1878                         return -EPERM;
1879                 }
1880         }
1881
1882         if (connman_element_ref(element) == NULL)
1883                 return -EINVAL;
1884
1885         __connman_element_lock(element);
1886
1887         if (element->name == NULL) {
1888                 element->name = g_strdup(type2string(element->type));
1889                 if (element->name == NULL) {
1890                         __connman_element_unlock(element);
1891                         return -EINVAL;
1892                 }
1893         }
1894
1895         element->parent = parent;
1896
1897         __connman_element_unlock(element);
1898
1899         register_element(element, NULL);
1900
1901         return 0;
1902 }
1903
1904 static gboolean remove_element(GNode *node, gpointer user_data)
1905 {
1906         struct connman_element *element = node->data;
1907         struct connman_element *root = user_data;
1908
1909         DBG("element %p name %s", element, element->name);
1910
1911         if (element == root)
1912                 return FALSE;
1913
1914         if (element->driver) {
1915                 disable_element(element);
1916
1917                 if (element->driver->remove)
1918                         element->driver->remove(element);
1919
1920                 __connman_element_lock(element);
1921                 element->driver = NULL;
1922                 __connman_element_unlock(element);
1923         }
1924
1925         if (node != NULL) {
1926                 g_node_unlink(node);
1927                 g_node_destroy(node);
1928         }
1929
1930         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1931                 emit_state_change(connection, "offline");
1932                 emit_connections_signal(connection);
1933
1934                 g_dbus_unregister_interface(connection, element->path,
1935                                                 CONNMAN_CONNECTION_INTERFACE);
1936         }
1937
1938         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1939                 emit_networks_signal(connection, element->parent);
1940
1941                 g_dbus_unregister_interface(connection, element->path,
1942                                                 CONNMAN_NETWORK_INTERFACE);
1943         }
1944
1945         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1946                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1947                 emit_devices_signal(connection);
1948
1949                 g_dbus_unregister_interface(connection, element->path,
1950                                                 CONNMAN_DEVICE_INTERFACE);
1951         }
1952
1953         connman_element_unref(element);
1954
1955         return FALSE;
1956 }
1957
1958 void connman_element_unregister(struct connman_element *element)
1959 {
1960         GNode *node;
1961
1962         DBG("element %p name %s", element, element->name);
1963
1964         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1965
1966         if (node != NULL)
1967                 g_node_traverse(node, G_POST_ORDER,
1968                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1969 }
1970
1971 void connman_element_unregister_children(struct connman_element *element)
1972 {
1973         GNode *node;
1974
1975         DBG("element %p name %s", element, element->name);
1976
1977         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1978
1979         if (node != NULL)
1980                 g_node_traverse(node, G_POST_ORDER,
1981                                 G_TRAVERSE_ALL, -1, remove_element, element);
1982 }
1983
1984 static gboolean update_element(GNode *node, gpointer user_data)
1985 {
1986         struct connman_element *element = node->data;
1987
1988         DBG("element %p name %s", element, element->name);
1989
1990         if (element->driver && element->driver->update)
1991                 element->driver->update(element);
1992
1993         return FALSE;
1994 }
1995
1996 void connman_element_update(struct connman_element *element)
1997 {
1998         GNode *node;
1999
2000         DBG("element %p name %s", element, element->name);
2001
2002         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2003
2004         if (node != NULL)
2005                 g_node_traverse(node, G_PRE_ORDER,
2006                                 G_TRAVERSE_ALL, -1, update_element, NULL);
2007 }
2008
2009 int connman_element_set_enabled(struct connman_element *element,
2010                                                         gboolean enabled)
2011 {
2012         if (element->enabled == enabled)
2013                 return 0;
2014
2015         element->enabled = enabled;
2016
2017         emit_enabled_signal(connection, element);
2018
2019         return 0;
2020 }
2021
2022 int __connman_element_init(DBusConnection *conn, const char *device)
2023 {
2024         struct connman_element *element;
2025
2026         DBG("conn %p", conn);
2027
2028         connection = dbus_connection_ref(conn);
2029         if (connection == NULL)
2030                 return -EIO;
2031
2032         device_filter = g_strdup(device);
2033
2034         element = connman_element_create("root");
2035
2036         element->path = g_strdup("/");
2037         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
2038
2039         create_default_properties(element);
2040
2041         element_root = g_node_new(element);
2042
2043         __connman_device_init();
2044
2045         return 0;
2046 }
2047
2048 static gboolean free_driver(GNode *node, gpointer data)
2049 {
2050         struct connman_element *element = node->data;
2051
2052         DBG("element %p name %s", element, element->name);
2053
2054         if (element->driver) {
2055                 disable_element(element);
2056
2057                 if (element->driver->remove)
2058                         element->driver->remove(element);
2059
2060                 __connman_element_lock(element);
2061                 element->driver = NULL;
2062                 __connman_element_unlock(element);
2063         }
2064
2065         return FALSE;
2066 }
2067
2068 static gboolean free_node(GNode *node, gpointer data)
2069 {
2070         struct connman_element *element = node->data;
2071
2072         DBG("element %p name %s", element, element->name);
2073
2074         if (g_node_depth(node) > 1)
2075                 connman_element_unregister(element);
2076
2077         return FALSE;
2078 }
2079
2080 void __connman_element_cleanup(void)
2081 {
2082         DBG("");
2083
2084         __connman_device_cleanup();
2085
2086         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2087                                                         free_driver, NULL);
2088
2089         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2090                                                         free_node, NULL);
2091
2092         g_node_destroy(element_root);
2093         element_root = NULL;
2094
2095         g_free(device_filter);
2096
2097         dbus_connection_unref(connection);
2098 }