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