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