Add skeleton for setting properties via D-Bus
[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
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 *set_property(DBusConnection *conn,
209                                         DBusMessage *msg, void *data)
210 {
211         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
212 }
213
214 static DBusMessage *do_update(DBusConnection *conn,
215                                         DBusMessage *msg, void *data)
216 {
217         struct connman_element *element = data;
218
219         DBG("conn %p", conn);
220
221         if (element->driver == NULL)
222                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
223
224         if (element->driver->update) {
225                 DBG("Calling update callback");
226                 element->driver->update(element);
227         }
228
229         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
230 }
231
232 static DBusMessage *do_connect(DBusConnection *conn,
233                                         DBusMessage *msg, void *data)
234 {
235         struct connman_element *element = data;
236
237         DBG("conn %p", conn);
238
239         if (element->driver == NULL)
240                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
241
242         if (element->driver->connect) {
243                 DBG("Calling connect callback");
244                 element->driver->connect(element);
245         }
246
247         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
248 }
249
250 static DBusMessage *do_disconnect(DBusConnection *conn,
251                                         DBusMessage *msg, void *data)
252 {
253         struct connman_element *element = data;
254
255         DBG("conn %p", conn);
256
257         if (element->driver == NULL)
258                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
259
260         if (element->driver->disconnect) {
261                 DBG("Calling disconnect callback");
262                 element->driver->disconnect(element);
263         }
264
265         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
266 }
267
268 static GDBusMethodTable element_methods[] = {
269         { "GetProperties", "",   "a{sv}", get_properties },
270         { "SetProperty",   "sv", "",      set_property   },
271         { "Update",        "",   "",      do_update      },
272         { "Connect",       "",   "",      do_connect     },
273         { "Disconnect",    "",   "",      do_disconnect  },
274         { },
275 };
276
277 struct append_filter {
278         enum connman_element_type type;
279         DBusMessageIter *iter;
280 };
281
282 static gboolean append_path(GNode *node, gpointer data)
283 {
284         struct connman_element *element = node->data;
285         struct append_filter *filter = data;
286
287         DBG("element %p name %s", element, element->name);
288
289         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
290                 return FALSE;
291
292         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
293                                         filter->type != element->type)
294                 return FALSE;
295
296         dbus_message_iter_append_basic(filter->iter,
297                                 DBUS_TYPE_OBJECT_PATH, &element->path);
298
299         return FALSE;
300 }
301
302 void __connman_element_list(enum connman_element_type type,
303                                                 DBusMessageIter *iter)
304 {
305         struct append_filter filter = { type, iter };
306
307         DBG("");
308
309         g_static_rw_lock_reader_lock(&element_lock);
310         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
311                                                         append_path, &filter);
312         g_static_rw_lock_reader_unlock(&element_lock);
313 }
314
315 static gint compare_priority(gconstpointer a, gconstpointer b)
316 {
317         const struct connman_driver *driver1 = a;
318         const struct connman_driver *driver2 = b;
319
320         return driver2->priority - driver1->priority;
321 }
322
323 static gboolean match_driver(struct connman_element *element,
324                                         struct connman_driver *driver)
325 {
326         if (element->type != driver->type &&
327                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
328                 return FALSE;
329
330         if (element->subtype == driver->subtype ||
331                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
332                 return TRUE;
333
334         return FALSE;
335 }
336
337 static gboolean probe_driver(GNode *node, gpointer data)
338 {
339         struct connman_element *element = node->data;
340         struct connman_driver *driver = data;
341
342         DBG("element %p name %s", element, element->name);
343
344         if (!element->driver && match_driver(element, driver) == TRUE) {
345                 if (driver->probe(element) < 0)
346                         return FALSE;
347
348                 connman_element_lock(element);
349                 element->driver = driver;
350                 connman_element_unlock(element);
351         }
352
353         return FALSE;
354 }
355
356 int connman_driver_register(struct connman_driver *driver)
357 {
358         DBG("driver %p name %s", driver, driver->name);
359
360         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
361                 return -EINVAL;
362
363         if (!driver->probe)
364                 return -EINVAL;
365
366         g_static_rw_lock_writer_lock(&element_lock);
367
368         driver_list = g_slist_insert_sorted(driver_list, driver,
369                                                         compare_priority);
370
371         if (element_root != NULL)
372                 g_node_traverse(element_root, G_PRE_ORDER,
373                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
374
375         g_static_rw_lock_writer_unlock(&element_lock);
376
377         return 0;
378 }
379
380 static gboolean remove_driver(GNode *node, gpointer data)
381 {
382         struct connman_element *element = node->data;
383         struct connman_driver *driver = data;
384
385         DBG("element %p name %s", element, element->name);
386
387         if (element->driver == driver) {
388                 if (driver->remove)
389                         driver->remove(element);
390
391                 connman_element_lock(element);
392                 element->driver = NULL;
393                 connman_element_unlock(element);
394         }
395
396         return FALSE;
397 }
398
399 void connman_driver_unregister(struct connman_driver *driver)
400 {
401         DBG("driver %p name %s", driver, driver->name);
402
403         g_static_rw_lock_writer_lock(&element_lock);
404
405         driver_list = g_slist_remove(driver_list, driver);
406
407         if (element_root != NULL)
408                 g_node_traverse(element_root, G_POST_ORDER,
409                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
410
411         g_static_rw_lock_writer_unlock(&element_lock);
412 }
413
414 struct connman_element *connman_element_create(void)
415 {
416         struct connman_element *element;
417
418         element = g_new0(struct connman_element, 1);
419
420         DBG("element %p", element);
421
422         element->refcount = 1;
423
424         g_static_mutex_init(&element->mutex);
425
426         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
427         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
428         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
429
430         element->connected = FALSE;
431
432         element->netdev.index = -1;
433
434         return element;
435 }
436
437 struct connman_element *connman_element_ref(struct connman_element *element)
438 {
439         DBG("element %p name %s refcount %d", element, element->name,
440                                 g_atomic_int_get(&element->refcount) + 1);
441
442         g_atomic_int_inc(&element->refcount);
443
444         return element;
445 }
446
447 void connman_element_unref(struct connman_element *element)
448 {
449         DBG("element %p name %s refcount %d", element, element->name,
450                                 g_atomic_int_get(&element->refcount) - 1);
451
452         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
453                 GSList *list;
454
455                 for (list = element->properties; list; list = list->next) {
456                         struct connman_property *property = list->data;
457                         if ((property->flags & CONNMAN_PROPERTY_FLAG_STATIC) &&
458                                         property->type == DBUS_TYPE_STRING)
459                                 g_free(property->value);
460                         g_free(property);
461                         list->data = NULL;
462                 }
463                 g_slist_free(element->properties);
464
465                 g_free(element->ipv4.address);
466                 g_free(element->ipv4.netmask);
467                 g_free(element->ipv4.gateway);
468                 g_free(element->ipv4.network);
469                 g_free(element->ipv4.broadcast);
470                 g_free(element->ipv4.nameserver);
471                 g_free(element->network.identifier);
472                 g_free(element->netdev.name);
473                 g_free(element->path);
474                 g_free(element->name);
475                 g_free(element);
476         }
477 }
478
479 int connman_element_add_static_property(struct connman_element *element,
480                                 const char *name, int type, const void *value)
481 {
482         struct connman_property *property;
483
484         DBG("element %p name %s", element, element->name);
485
486         if (type != DBUS_TYPE_STRING)
487                 return -EINVAL;
488
489         property = g_try_new0(struct connman_property, 1);
490         if (property == NULL)
491                 return -ENOMEM;
492
493         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
494
495         property->name = g_strdup(name);
496         property->type = type;
497
498         DBG("name %s type %d value %p", name, type, value);
499
500         switch (type) {
501         case DBUS_TYPE_STRING:
502                 property->value = g_strdup(*((const char **) value));
503                 break;
504         }
505
506         connman_element_lock(element);
507         element->properties = g_slist_append(element->properties, property);
508         connman_element_unlock(element);
509
510         return 0;
511 }
512
513 int connman_element_set_property(struct connman_element *element,
514                         enum connman_property_type type, const void *value)
515 {
516         switch (type) {
517         case CONNMAN_PROPERTY_TYPE_INVALID:
518                 return -EINVAL;
519         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
520                 connman_element_lock(element);
521                 g_free(element->ipv4.address);
522                 element->ipv4.address = g_strdup(*((const char **) value));
523                 connman_element_unlock(element);
524                 break;
525         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
526                 connman_element_lock(element);
527                 g_free(element->ipv4.netmask);
528                 element->ipv4.netmask = g_strdup(*((const char **) value));
529                 connman_element_unlock(element);
530                 break;
531         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
532                 connman_element_lock(element);
533                 g_free(element->ipv4.gateway);
534                 element->ipv4.gateway = g_strdup(*((const char **) value));
535                 connman_element_unlock(element);
536                 break;
537         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
538                 connman_element_lock(element);
539                 g_free(element->ipv4.nameserver);
540                 element->ipv4.nameserver = g_strdup(*((const char **) value));
541                 connman_element_unlock(element);
542                 break;
543         }
544
545         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
546                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
547                                 DBUS_TYPE_OBJECT_PATH, &element->path,
548                                                         DBUS_TYPE_INVALID);
549
550         return 0;
551 }
552
553 int connman_element_get_value(struct connman_element *element,
554                                 enum connman_property_type type, void *value)
555 {
556         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
557                 return -EINVAL;
558
559         switch (type) {
560         case CONNMAN_PROPERTY_TYPE_INVALID:
561                 return -EINVAL;
562         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
563                 if (element->ipv4.address == NULL)
564                         return connman_element_get_value(element->parent,
565                                                                 type, value);
566                 connman_element_lock(element);
567                 *((char **) value) = element->ipv4.address;
568                 connman_element_unlock(element);
569                 break;
570         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
571                 if (element->ipv4.netmask == NULL)
572                         return connman_element_get_value(element->parent,
573                                                                 type, value);
574                 connman_element_lock(element);
575                 *((char **) value) = element->ipv4.netmask;
576                 connman_element_unlock(element);
577                 break;
578         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
579                 if (element->ipv4.gateway == NULL)
580                         return connman_element_get_value(element->parent,
581                                                                 type, value);
582                 connman_element_lock(element);
583                 *((char **) value) = element->ipv4.gateway;
584                 connman_element_unlock(element);
585                 break;
586         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
587                 if (element->ipv4.nameserver == NULL)
588                         return connman_element_get_value(element->parent,
589                                                                 type, value);
590                 connman_element_lock(element);
591                 *((char **) value) = element->ipv4.nameserver;
592                 connman_element_unlock(element);
593                 break;
594         }
595
596         return 0;
597 }
598
599 int connman_element_register(struct connman_element *element,
600                                         struct connman_element *parent)
601 {
602         DBG("element %p name %s parent %p", element, element->name, parent);
603
604         if (connman_element_ref(element) == NULL)
605                 return -EINVAL;
606
607         connman_element_lock(element);
608
609         __connman_element_load(element);
610
611         if (element->name == NULL) {
612                 switch (element->type) {
613                 case CONNMAN_ELEMENT_TYPE_IPV4:
614                         element->name = g_strdup("ipv4");
615                         break;
616                 case CONNMAN_ELEMENT_TYPE_IPV6:
617                         element->name = g_strdup("ipv6");
618                         break;
619                 case CONNMAN_ELEMENT_TYPE_DHCP:
620                         element->name = g_strdup("dhcp");
621                         break;
622                 case CONNMAN_ELEMENT_TYPE_BOOTP:
623                         element->name = g_strdup("bootp");
624                         break;
625                 case CONNMAN_ELEMENT_TYPE_ZEROCONF:
626                         element->name = g_strdup("zeroconf");
627                         break;
628                 case CONNMAN_ELEMENT_TYPE_RESOLVER:
629                         element->name = g_strdup("resolver");
630                         break;
631                 case CONNMAN_ELEMENT_TYPE_INTERNET:
632                         element->name = g_strdup("internet");
633                         break;
634                 default:
635                         break;
636                 }
637         }
638
639         element->parent = parent;
640
641         connman_element_unlock(element);
642
643         if (thread_register != NULL)
644                 g_thread_pool_push(thread_register, element, NULL);
645
646         return 0;
647 }
648
649 void connman_element_unregister(struct connman_element *element)
650 {
651         DBG("element %p name %s", element, element->name);
652
653         if (thread_unregister != NULL)
654                 g_thread_pool_push(thread_unregister, element, NULL);
655 }
656
657 void connman_element_update(struct connman_element *element)
658 {
659         DBG("element %p name %s", element, element->name);
660
661         g_static_rw_lock_reader_lock(&element_lock);
662
663         if (element->driver && element->driver->update)
664                 element->driver->update(element);
665
666         g_static_rw_lock_reader_unlock(&element_lock);
667
668         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
669                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
670                                 DBUS_TYPE_OBJECT_PATH, &element->path,
671                                                         DBUS_TYPE_INVALID);
672 }
673
674 static void register_element(gpointer data, gpointer user_data)
675 {
676         struct connman_element *element = data;
677         const gchar *basepath;
678         GSList *list;
679         GNode *node;
680
681         g_static_rw_lock_writer_lock(&element_lock);
682
683         connman_element_lock(element);
684
685         if (element->parent) {
686                 node = g_node_find(element_root, G_PRE_ORDER,
687                                         G_TRAVERSE_ALL, element->parent);
688                 basepath = element->parent->path;
689
690                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
691                         element->subtype = element->parent->subtype;
692         } else {
693                 node = element_root;
694                 basepath = "";
695         }
696
697         element->path = g_strdup_printf("%s/%s", basepath, element->name);
698
699         connman_element_unlock(element);
700
701         DBG("element %p path %s", element, element->path);
702
703         g_node_append_data(node, element);
704
705         g_static_rw_lock_writer_unlock(&element_lock);
706
707         __connman_element_store(element);
708
709         if (g_dbus_register_interface(connection, element->path,
710                                         CONNMAN_ELEMENT_INTERFACE,
711                                         element_methods, NULL, NULL,
712                                                 element, NULL) == FALSE)
713                 connman_error("Failed to register %s", element->path);
714
715         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
716                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
717                                 DBUS_TYPE_OBJECT_PATH, &element->path,
718                                                         DBUS_TYPE_INVALID);
719
720         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
721                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
722                                 CONNMAN_MANAGER_INTERFACE, "DeviceAdded",
723                                 DBUS_TYPE_OBJECT_PATH, &element->path,
724                                                         DBUS_TYPE_INVALID);
725
726         g_static_rw_lock_writer_lock(&element_lock);
727
728         for (list = driver_list; list; list = list->next) {
729                 struct connman_driver *driver = list->data;
730
731                 if (match_driver(element, driver) == FALSE)
732                         continue;
733
734                 DBG("driver %p name %s", driver, driver->name);
735
736                 if (driver->probe(element) < 0)
737                         continue;
738
739                 connman_element_lock(element);
740                 element->driver = driver;
741                 connman_element_unlock(element);
742         }
743
744         g_static_rw_lock_writer_unlock(&element_lock);
745 }
746
747 static void unregister_element(gpointer data, gpointer user_data)
748 {
749         struct connman_element *element = data;
750         GNode *node;
751
752         DBG("element %p name %s", element, element->name);
753
754         g_static_rw_lock_writer_lock(&element_lock);
755
756         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
757
758         if (element->driver) {
759                 if (element->driver->remove)
760                         element->driver->remove(element);
761
762                 connman_element_lock(element);
763                 element->driver = NULL;
764                 connman_element_unlock(element);
765         }
766
767         if (node != NULL) {
768                 g_node_unlink(node);
769                 g_node_destroy(node);
770         }
771
772         g_static_rw_lock_writer_unlock(&element_lock);
773
774         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE)
775                 g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
776                                 CONNMAN_MANAGER_INTERFACE, "DeviceRemoved",
777                                 DBUS_TYPE_OBJECT_PATH, &element->path,
778                                                         DBUS_TYPE_INVALID);
779
780         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
781                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
782                                 DBUS_TYPE_OBJECT_PATH, &element->path,
783                                                         DBUS_TYPE_INVALID);
784
785         g_dbus_unregister_interface(connection, element->path,
786                                                 CONNMAN_ELEMENT_INTERFACE);
787
788         connman_element_unref(element);
789 }
790
791 int __connman_element_init(DBusConnection *conn)
792 {
793         struct connman_element *element;
794
795         DBG("conn %p", conn);
796
797         connection = dbus_connection_ref(conn);
798         if (connection == NULL)
799                 return -EIO;
800
801         g_static_rw_lock_writer_lock(&element_lock);
802
803         element = connman_element_create();
804
805         element->name = g_strdup("root");
806         element->path = g_strdup("/");
807         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
808
809         element_root = g_node_new(element);
810
811         g_static_rw_lock_writer_unlock(&element_lock);
812
813         thread_register = g_thread_pool_new(register_element,
814                                                         NULL, 1, FALSE, NULL);
815         thread_unregister = g_thread_pool_new(unregister_element,
816                                                         NULL, 1, FALSE, NULL);
817
818         return 0;
819 }
820
821 static gboolean free_driver(GNode *node, gpointer data)
822 {
823         struct connman_element *element = node->data;
824
825         DBG("element %p name %s", element, element->name);
826
827         if (element->driver) {
828                 if (element->driver->remove)
829                         element->driver->remove(element);
830
831                 connman_element_lock(element);
832                 element->driver = NULL;
833                 connman_element_unlock(element);
834         }
835
836         return FALSE;
837 }
838
839 static gboolean free_node(GNode *node, gpointer data)
840 {
841         struct connman_element *element = node->data;
842
843         DBG("element %p name %s", element, element->name);
844
845         if (g_node_depth(node) > 1)
846                 g_thread_pool_push(thread_unregister, element, NULL);
847
848         return FALSE;
849 }
850
851 void __connman_element_cleanup(void)
852 {
853         DBG("");
854
855         g_thread_pool_free(thread_register, TRUE, TRUE);
856         thread_register = NULL;
857
858         g_static_rw_lock_writer_lock(&element_lock);
859         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
860                                                         free_driver, NULL);
861         g_static_rw_lock_writer_unlock(&element_lock);
862
863         g_static_rw_lock_writer_lock(&element_lock);
864         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
865                                                         free_node, NULL);
866         g_static_rw_lock_writer_unlock(&element_lock);
867
868         g_thread_pool_free(thread_unregister, FALSE, TRUE);
869         thread_unregister = NULL;
870
871         g_static_rw_lock_writer_lock(&element_lock);
872         g_node_destroy(element_root);
873         element_root = NULL;
874         g_static_rw_lock_writer_unlock(&element_lock);
875
876         dbus_connection_unref(connection);
877 }