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