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