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