Add support for Update method via D-Bus
[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
28 #include <glib.h>
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection;
34
35 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
36 static GNode *element_root = NULL;
37
38 static GSList *driver_list = NULL;
39
40 static GThreadPool *thread_register = NULL;
41 static GThreadPool *thread_unregister = NULL;
42
43 static const char *type2string(enum connman_element_type type)
44 {
45         switch (type) {
46         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
47                 return "unknown";
48         case CONNMAN_ELEMENT_TYPE_ROOT:
49                 return "root";
50         case CONNMAN_ELEMENT_TYPE_DEVICE:
51                 return "device";
52         case CONNMAN_ELEMENT_TYPE_NETWORK:
53                 return "network";
54         case CONNMAN_ELEMENT_TYPE_IPV4:
55                 return "ipv4";
56         case CONNMAN_ELEMENT_TYPE_IPV6:
57                 return "ipv6";
58         case CONNMAN_ELEMENT_TYPE_DHCP:
59                 return "dhcp";
60         case CONNMAN_ELEMENT_TYPE_BOOTP:
61                 return "bootp";
62         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
63                 return "zeroconf";
64         case CONNMAN_ELEMENT_TYPE_RESOLVER:
65                 return "resolver";
66         case CONNMAN_ELEMENT_TYPE_INTERNET:
67                 return "internet";
68         }
69
70         return NULL;
71 }
72
73 static const char *subtype2string(enum connman_element_subtype type)
74 {
75         switch (type) {
76         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
77                 return "unknown";
78         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
79                 return "ethernet";
80         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
81                 return "wifi";
82         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
83                 return "wimax";
84         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
85                 return "modem";
86         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
87                 return "bluetooth";
88         }
89
90         return NULL;
91 }
92
93 static void append_entry(DBusMessageIter *dict,
94                                 const char *key, int type, void *val)
95 {
96         DBusMessageIter entry, value;
97         const char *signature;
98
99         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
100                                                                 NULL, &entry);
101
102         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
103
104         switch (type) {
105         case DBUS_TYPE_BOOLEAN:
106                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
107                 break;
108         case DBUS_TYPE_STRING:
109                 signature = DBUS_TYPE_STRING_AS_STRING;
110                 break;
111         case DBUS_TYPE_UINT16:
112                 signature = DBUS_TYPE_UINT16_AS_STRING;
113                 break;
114         case DBUS_TYPE_UINT32:
115                 signature = DBUS_TYPE_UINT32_AS_STRING;
116                 break;
117         case DBUS_TYPE_OBJECT_PATH:
118                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
119                 break;
120         default:
121                 signature = DBUS_TYPE_VARIANT_AS_STRING;
122                 break;
123         }
124
125         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
126                                                         signature, &value);
127         dbus_message_iter_append_basic(&value, type, val);
128         dbus_message_iter_close_container(&entry, &value);
129
130         dbus_message_iter_close_container(dict, &entry);
131 }
132
133 static void append_property(DBusMessageIter *dict,
134                                 struct connman_property *property)
135 {
136         if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC) {
137                 append_entry(dict, property->name, property->type,
138                                                         &property->value);
139                 return;
140         }
141 }
142
143 static DBusMessage *get_properties(DBusConnection *conn,
144                                         DBusMessage *msg, void *data)
145 {
146         struct connman_element *element = data;
147         GSList *list;
148         DBusMessage *reply;
149         DBusMessageIter array, dict;
150         const char *str;
151
152         DBG("conn %p", conn);
153
154         reply = dbus_message_new_method_return(msg);
155         if (reply == NULL)
156                 return NULL;
157
158         dbus_message_iter_init_append(reply, &array);
159
160         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
161                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
162                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
163                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
164
165         if (element->parent != NULL)
166                 append_entry(&dict, "Parent",
167                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
168
169         str = type2string(element->type);
170         if (str != NULL)
171                 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
172         str = subtype2string(element->subtype);
173         if (str != NULL)
174                 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
175
176         append_entry(&dict, "Connected",
177                                 DBUS_TYPE_BOOLEAN, &element->connected);
178
179         if (element->priority > 0)
180                 append_entry(&dict, "Priority",
181                                 DBUS_TYPE_UINT16, &element->priority);
182
183         if (element->network.identifier != NULL)
184                 append_entry(&dict, "Identifier",
185                                 DBUS_TYPE_STRING, &element->network.identifier);
186
187         if (element->ipv4.address != NULL)
188                 append_entry(&dict, "IPv4.Address",
189                                 DBUS_TYPE_STRING, &element->ipv4.address);
190         if (element->ipv4.netmask != NULL)
191                 append_entry(&dict, "IPv4.Netmask",
192                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
193         if (element->ipv4.gateway != NULL)
194                 append_entry(&dict, "IPv4.Gateway",
195                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
196
197         for (list = element->properties; list; list = list->next) {
198                 struct connman_property *property = list->data;
199
200                 append_property(&dict, property);
201         }
202
203         dbus_message_iter_close_container(&array, &dict);
204
205         return reply;
206 }
207
208 static DBusMessage *do_update(DBusConnection *conn,
209                                         DBusMessage *msg, void *data)
210 {
211         struct connman_element *element = data;
212
213         DBG("conn %p", conn);
214
215         if (element->driver == NULL)
216                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
217
218         if (element->driver->update) {
219                 DBG("Calling update callback");
220                 element->driver->update(element);
221         }
222
223         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
224 }
225
226 static DBusMessage *do_connect(DBusConnection *conn,
227                                         DBusMessage *msg, void *data)
228 {
229         struct connman_element *element = data;
230
231         DBG("conn %p", conn);
232
233         if (element->driver == NULL)
234                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
235
236         if (element->driver->connect) {
237                 DBG("Calling connect callback");
238                 element->driver->connect(element);
239         }
240
241         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
242 }
243
244 static DBusMessage *do_disconnect(DBusConnection *conn,
245                                         DBusMessage *msg, void *data)
246 {
247         struct connman_element *element = data;
248
249         DBG("conn %p", conn);
250
251         if (element->driver == NULL)
252                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
253
254         if (element->driver->disconnect) {
255                 DBG("Calling disconnect callback");
256                 element->driver->disconnect(element);
257         }
258
259         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
260 }
261
262 static GDBusMethodTable element_methods[] = {
263         { "GetProperties", "", "a{sv}", get_properties },
264         { "Update",        "", "",      do_update      },
265         { "Connect",       "", "",      do_connect     },
266         { "Disconnect",    "", "",      do_disconnect  },
267         { },
268 };
269
270 struct append_filter {
271         enum connman_element_type type;
272         DBusMessageIter *iter;
273 };
274
275 static gboolean append_path(GNode *node, gpointer data)
276 {
277         struct connman_element *element = node->data;
278         struct append_filter *filter = data;
279
280         DBG("element %p name %s", element, element->name);
281
282         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
283                 return FALSE;
284
285         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
286                                         filter->type != element->type)
287                 return FALSE;
288
289         dbus_message_iter_append_basic(filter->iter,
290                                 DBUS_TYPE_OBJECT_PATH, &element->path);
291
292         return FALSE;
293 }
294
295 void __connman_element_list(enum connman_element_type type,
296                                                 DBusMessageIter *iter)
297 {
298         struct append_filter filter = { type, iter };
299
300         DBG("");
301
302         g_static_rw_lock_reader_lock(&element_lock);
303         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
304                                                         append_path, &filter);
305         g_static_rw_lock_reader_unlock(&element_lock);
306 }
307
308 static gint compare_priority(gconstpointer a, gconstpointer b)
309 {
310         const struct connman_driver *driver1 = a;
311         const struct connman_driver *driver2 = b;
312
313         return driver2->priority - driver1->priority;
314 }
315
316 static gboolean match_driver(struct connman_element *element,
317                                         struct connman_driver *driver)
318 {
319         if (element->type != driver->type &&
320                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
321                 return FALSE;
322
323         if (element->subtype == driver->subtype ||
324                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
325                 return TRUE;
326
327         return FALSE;
328 }
329
330 static gboolean probe_driver(GNode *node, gpointer data)
331 {
332         struct connman_element *element = node->data;
333         struct connman_driver *driver = data;
334
335         DBG("element %p name %s", element, element->name);
336
337         if (!element->driver && match_driver(element, driver) == TRUE) {
338                 if (driver->probe(element) < 0)
339                         return FALSE;
340
341                 connman_element_lock(element);
342                 element->driver = driver;
343                 connman_element_unlock(element);
344         }
345
346         return FALSE;
347 }
348
349 int connman_driver_register(struct connman_driver *driver)
350 {
351         DBG("driver %p name %s", driver, driver->name);
352
353         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
354                 return -EINVAL;
355
356         if (!driver->probe)
357                 return -EINVAL;
358
359         g_static_rw_lock_writer_lock(&element_lock);
360
361         driver_list = g_slist_insert_sorted(driver_list, driver,
362                                                         compare_priority);
363
364         if (element_root != NULL)
365                 g_node_traverse(element_root, G_PRE_ORDER,
366                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
367
368         g_static_rw_lock_writer_unlock(&element_lock);
369
370         return 0;
371 }
372
373 static gboolean remove_driver(GNode *node, gpointer data)
374 {
375         struct connman_element *element = node->data;
376         struct connman_driver *driver = data;
377
378         DBG("element %p name %s", element, element->name);
379
380         if (element->driver == driver) {
381                 if (driver->remove)
382                         driver->remove(element);
383
384                 connman_element_lock(element);
385                 element->driver = NULL;
386                 connman_element_unlock(element);
387         }
388
389         return FALSE;
390 }
391
392 void connman_driver_unregister(struct connman_driver *driver)
393 {
394         DBG("driver %p name %s", driver, driver->name);
395
396         g_static_rw_lock_writer_lock(&element_lock);
397
398         driver_list = g_slist_remove(driver_list, driver);
399
400         if (element_root != NULL)
401                 g_node_traverse(element_root, G_POST_ORDER,
402                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
403
404         g_static_rw_lock_writer_unlock(&element_lock);
405 }
406
407 struct connman_element *connman_element_create(void)
408 {
409         struct connman_element *element;
410
411         element = g_new0(struct connman_element, 1);
412
413         DBG("element %p", element);
414
415         element->refcount = 1;
416
417         g_static_mutex_init(&element->mutex);
418
419         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
420         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
421         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
422
423         element->connected = FALSE;
424
425         element->netdev.index = -1;
426
427         return element;
428 }
429
430 struct connman_element *connman_element_ref(struct connman_element *element)
431 {
432         DBG("element %p name %s refcount %d", element, element->name,
433                                 g_atomic_int_get(&element->refcount) + 1);
434
435         g_atomic_int_inc(&element->refcount);
436
437         return element;
438 }
439
440 void connman_element_unref(struct connman_element *element)
441 {
442         DBG("element %p name %s refcount %d", element, element->name,
443                                 g_atomic_int_get(&element->refcount) - 1);
444
445         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
446                 GSList *list;
447
448                 for (list = element->properties; list; list = list->next) {
449                         struct connman_property *property = list->data;
450                         if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
451                                         property->type == DBUS_TYPE_STRING)
452                                 g_free(property->value);
453                         g_free(property);
454                         list->data = NULL;
455                 }
456                 g_slist_free(element->properties);
457
458                 g_free(element->ipv4.address);
459                 g_free(element->ipv4.netmask);
460                 g_free(element->ipv4.gateway);
461                 g_free(element->ipv4.network);
462                 g_free(element->ipv4.broadcast);
463                 g_free(element->ipv4.nameserver);
464                 g_free(element->network.identifier);
465                 g_free(element->netdev.name);
466                 g_free(element->path);
467                 g_free(element->name);
468                 g_free(element);
469         }
470 }
471
472 int connman_element_add_static_property(struct connman_element *element,
473                                 const char *name, int type, const void *value)
474 {
475         struct connman_property *property;
476
477         DBG("element %p name %s", element, element->name);
478
479         if (type != DBUS_TYPE_STRING)
480                 return -EINVAL;
481
482         property = g_try_new0(struct connman_property, 1);
483         if (property == NULL)
484                 return -ENOMEM;
485
486         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
487
488         property->name = g_strdup(name);
489         property->type = type;
490
491         DBG("name %s type %d value %p", name, type, value);
492
493         switch (type) {
494         case DBUS_TYPE_STRING:
495                 property->value = g_strdup(*((const char **) value));
496                 break;
497         }
498
499         connman_element_lock(element);
500         element->properties = g_slist_append(element->properties, property);
501         connman_element_unlock(element);
502
503         return 0;
504 }
505
506 int connman_element_set_property(struct connman_element *element,
507                         enum connman_property_type type, const void *value)
508 {
509         switch (type) {
510         case CONNMAN_PROPERTY_TYPE_INVALID:
511                 return -EINVAL;
512         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
513                 connman_element_lock(element);
514                 g_free(element->ipv4.address);
515                 element->ipv4.address = g_strdup(*((const char **) value));
516                 connman_element_unlock(element);
517                 break;
518         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
519                 connman_element_lock(element);
520                 g_free(element->ipv4.netmask);
521                 element->ipv4.netmask = g_strdup(*((const char **) value));
522                 connman_element_unlock(element);
523                 break;
524         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
525                 connman_element_lock(element);
526                 g_free(element->ipv4.gateway);
527                 element->ipv4.gateway = g_strdup(*((const char **) value));
528                 connman_element_unlock(element);
529                 break;
530         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
531                 connman_element_lock(element);
532                 g_free(element->ipv4.nameserver);
533                 element->ipv4.nameserver = g_strdup(*((const char **) value));
534                 connman_element_unlock(element);
535                 break;
536         }
537
538         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
539                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
540                                 DBUS_TYPE_OBJECT_PATH, &element->path,
541                                                         DBUS_TYPE_INVALID);
542
543         return 0;
544 }
545
546 int connman_element_get_value(struct connman_element *element,
547                                 enum connman_property_type type, void *value)
548 {
549         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
550                 return -EINVAL;
551
552         switch (type) {
553         case CONNMAN_PROPERTY_TYPE_INVALID:
554                 return -EINVAL;
555         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
556                 if (element->ipv4.address == NULL)
557                         return connman_element_get_value(element->parent,
558                                                                 type, value);
559                 connman_element_lock(element);
560                 *((char **) value) = element->ipv4.address;
561                 connman_element_unlock(element);
562                 break;
563         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
564                 if (element->ipv4.netmask == NULL)
565                         return connman_element_get_value(element->parent,
566                                                                 type, value);
567                 connman_element_lock(element);
568                 *((char **) value) = element->ipv4.netmask;
569                 connman_element_unlock(element);
570                 break;
571         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
572                 if (element->ipv4.gateway == NULL)
573                         return connman_element_get_value(element->parent,
574                                                                 type, value);
575                 connman_element_lock(element);
576                 *((char **) value) = element->ipv4.gateway;
577                 connman_element_unlock(element);
578                 break;
579         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
580                 if (element->ipv4.nameserver == NULL)
581                         return connman_element_get_value(element->parent,
582                                                                 type, value);
583                 connman_element_lock(element);
584                 *((char **) value) = element->ipv4.nameserver;
585                 connman_element_unlock(element);
586                 break;
587         }
588
589         return 0;
590 }
591
592 int connman_element_register(struct connman_element *element,
593                                         struct connman_element *parent)
594 {
595         DBG("element %p name %s parent %p", element, element->name, parent);
596
597         if (connman_element_ref(element) == NULL)
598                 return -EINVAL;
599
600         connman_element_lock(element);
601
602         __connman_element_load(element);
603
604         if (element->name == NULL) {
605                 switch (element->type) {
606                 case CONNMAN_ELEMENT_TYPE_IPV4:
607                         element->name = g_strdup("ipv4");
608                         break;
609                 case CONNMAN_ELEMENT_TYPE_IPV6:
610                         element->name = g_strdup("ipv6");
611                         break;
612                 case CONNMAN_ELEMENT_TYPE_DHCP:
613                         element->name = g_strdup("dhcp");
614                         break;
615                 case CONNMAN_ELEMENT_TYPE_BOOTP:
616                         element->name = g_strdup("bootp");
617                         break;
618                 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
619                         element->name = g_strdup("zeroconf");
620                         break;
621                 case CONNMAN_ELEMENT_TYPE_RESOLVER:
622                         element->name = g_strdup("resolver");
623                         break;
624                 case CONNMAN_ELEMENT_TYPE_INTERNET:
625                         element->name = g_strdup("internet");
626                         break;
627                 default:
628                         break;
629                 }
630         }
631
632         element->parent = parent;
633
634         connman_element_unlock(element);
635
636         if (thread_register != NULL)
637                 g_thread_pool_push(thread_register, element, NULL);
638
639         return 0;
640 }
641
642 void connman_element_unregister(struct connman_element *element)
643 {
644         DBG("element %p name %s", element, element->name);
645
646         if (thread_unregister != NULL)
647                 g_thread_pool_push(thread_unregister, element, NULL);
648 }
649
650 void connman_element_update(struct connman_element *element)
651 {
652         DBG("element %p name %s", element, element->name);
653
654         g_static_rw_lock_reader_lock(&element_lock);
655
656         if (element->driver && element->driver->update)
657                 element->driver->update(element);
658
659         g_static_rw_lock_reader_unlock(&element_lock);
660
661         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
662                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
663                                 DBUS_TYPE_OBJECT_PATH, &element->path,
664                                                         DBUS_TYPE_INVALID);
665 }
666
667 static void register_element(gpointer data, gpointer user_data)
668 {
669         struct connman_element *element = data;
670         const gchar *basepath;
671         GSList *list;
672         GNode *node;
673
674         g_static_rw_lock_writer_lock(&element_lock);
675
676         connman_element_lock(element);
677
678         if (element->parent) {
679                 node = g_node_find(element_root, G_PRE_ORDER,
680                                         G_TRAVERSE_ALL, element->parent);
681                 basepath = element->parent->path;
682
683                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
684                         element->subtype = element->parent->subtype;
685         } else {
686                 node = element_root;
687                 basepath = "";
688         }
689
690         element->path = g_strdup_printf("%s/%s", basepath, element->name);
691
692         connman_element_unlock(element);
693
694         DBG("element %p path %s", element, element->path);
695
696         g_node_append_data(node, element);
697
698         g_static_rw_lock_writer_unlock(&element_lock);
699
700         __connman_element_store(element);
701
702         if (g_dbus_register_interface(connection, element->path,
703                                         CONNMAN_ELEMENT_INTERFACE,
704                                         element_methods, NULL, NULL,
705                                                 element, NULL) == FALSE)
706                 connman_error("Failed to register %s", element->path);
707
708         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
709                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
710                                 DBUS_TYPE_OBJECT_PATH, &element->path,
711                                                         DBUS_TYPE_INVALID);
712
713         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
714                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
715                                 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
716                                 DBUS_TYPE_OBJECT_PATH, &element->path,
717                                                         DBUS_TYPE_INVALID);
718
719         g_static_rw_lock_writer_lock(&element_lock);
720
721         for (list = driver_list; list; list = list->next) {
722                 struct connman_driver *driver = list->data;
723
724                 if (match_driver(element, driver) == FALSE)
725                         continue;
726
727                 DBG("driver %p name %s", driver, driver->name);
728
729                 if (driver->probe(element) < 0)
730                         continue;
731
732                 connman_element_lock(element);
733                 element->driver = driver;
734                 connman_element_unlock(element);
735         }
736
737         g_static_rw_lock_writer_unlock(&element_lock);
738 }
739
740 static void unregister_element(gpointer data, gpointer user_data)
741 {
742         struct connman_element *element = data;
743         GNode *node;
744
745         DBG("element %p name %s", element, element->name);
746
747         g_static_rw_lock_writer_lock(&element_lock);
748
749         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
750
751         if (element->driver) {
752                 if (element->driver->remove)
753                         element->driver->remove(element);
754
755                 connman_element_lock(element);
756                 element->driver = NULL;
757                 connman_element_unlock(element);
758         }
759
760         if (node != NULL) {
761                 g_node_unlink(node);
762                 g_node_destroy(node);
763         }
764
765         g_static_rw_lock_writer_unlock(&element_lock);
766
767         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
768                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
769                                 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
770                                 DBUS_TYPE_OBJECT_PATH, &element->path,
771                                                         DBUS_TYPE_INVALID);
772
773         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
774                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
775                                 DBUS_TYPE_OBJECT_PATH, &element->path,
776                                                         DBUS_TYPE_INVALID);
777
778         g_dbus_unregister_interface(connection, element->path,
779                                                 CONNMAN_ELEMENT_INTERFACE);
780
781         connman_element_unref(element);
782 }
783
784 int __connman_element_init(DBusConnection *conn)
785 {
786         struct connman_element *element;
787
788         DBG("conn %p", conn);
789
790         connection = dbus_connection_ref(conn);
791         if (connection == NULL)
792                 return -EIO;
793
794         g_static_rw_lock_writer_lock(&element_lock);
795
796         element = connman_element_create();
797
798         element->name = g_strdup("root");
799         element->path = g_strdup("/");
800         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
801
802         element_root = g_node_new(element);
803
804         g_static_rw_lock_writer_unlock(&element_lock);
805
806         thread_register = g_thread_pool_new(register_element,
807                                                         NULL, 1, FALSE, NULL);
808         thread_unregister = g_thread_pool_new(unregister_element,
809                                                         NULL, 1, FALSE, NULL);
810
811         return 0;
812 }
813
814 static gboolean free_driver(GNode *node, gpointer data)
815 {
816         struct connman_element *element = node->data;
817
818         DBG("element %p name %s", element, element->name);
819
820         if (element->driver) {
821                 if (element->driver->remove)
822                         element->driver->remove(element);
823
824                 connman_element_lock(element);
825                 element->driver = NULL;
826                 connman_element_unlock(element);
827         }
828
829         return FALSE;
830 }
831
832 static gboolean free_node(GNode *node, gpointer data)
833 {
834         struct connman_element *element = node->data;
835
836         DBG("element %p name %s", element, element->name);
837
838         if (g_node_depth(node) > 1)
839                 g_thread_pool_push(thread_unregister, element, NULL);
840
841         return FALSE;
842 }
843
844 void __connman_element_cleanup(void)
845 {
846         DBG("");
847
848         g_thread_pool_free(thread_register, TRUE, TRUE);
849         thread_register = NULL;
850
851         g_static_rw_lock_writer_lock(&element_lock);
852         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
853                                                         free_driver, NULL);
854         g_static_rw_lock_writer_unlock(&element_lock);
855
856         g_static_rw_lock_writer_lock(&element_lock);
857         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
858                                                         free_node, NULL);
859         g_static_rw_lock_writer_unlock(&element_lock);
860
861         g_thread_pool_free(thread_unregister, FALSE, TRUE);
862         thread_unregister = NULL;
863
864         g_static_rw_lock_writer_lock(&element_lock);
865         g_node_destroy(element_root);
866         element_root = NULL;
867         g_static_rw_lock_writer_unlock(&element_lock);
868
869         dbus_connection_unref(connection);
870 }