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