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