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