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