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