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