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