Remove backup files at cleanup stage
[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 #include <stdarg.h>
28
29 #include <glib.h>
30 #include <gdbus.h>
31
32 #include "connman.h"
33
34 static DBusConnection *connection;
35
36 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
37 static GNode *element_root = NULL;
38
39 static GSList *driver_list = NULL;
40
41 static GThreadPool *thread_register = NULL;
42 static GThreadPool *thread_unregister = NULL;
43 static GThreadPool *thread_unregister_children = NULL;
44
45 static gchar *device_filter = NULL;
46
47 static struct {
48         enum connman_property_id id;
49         int type;
50         const char *name;
51         const void *value;
52 } propid_table[] = {
53         { CONNMAN_PROPERTY_ID_IPV4_METHOD,
54                 DBUS_TYPE_STRING, "IPv4.Method", "dhcp" },
55         { CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
56                 DBUS_TYPE_STRING, "IPv4.Address" },
57         { CONNMAN_PROPERTY_ID_IPV4_NETMASK,
58                 DBUS_TYPE_STRING, "IPv4.Netmask" },
59         { CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
60                 DBUS_TYPE_STRING, "IPv4.Gateway" },
61         { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
62                 DBUS_TYPE_STRING, "IPv4.Nameserver" },
63         { }
64 };
65
66 static int propid2type(enum connman_property_id id)
67 {
68         int i;
69
70         for (i = 0; propid_table[i].name; i++) {
71                 if (propid_table[i].id == id)
72                         return propid_table[i].type;
73         }
74
75         return DBUS_TYPE_INVALID;
76 }
77
78 static const char *propid2name(enum connman_property_id id)
79 {
80         int i;
81
82         for (i = 0; propid_table[i].name; i++) {
83                 if (propid_table[i].id == id)
84                         return propid_table[i].name;
85         }
86
87         return NULL;
88 }
89
90 static const char *type2string(enum connman_element_type type)
91 {
92         switch (type) {
93         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
94                 return "unknown";
95         case CONNMAN_ELEMENT_TYPE_ROOT:
96                 return "root";
97         case CONNMAN_ELEMENT_TYPE_DEVICE:
98                 return "device";
99         case CONNMAN_ELEMENT_TYPE_NETWORK:
100                 return "network";
101         case CONNMAN_ELEMENT_TYPE_IPV4:
102                 return "ipv4";
103         case CONNMAN_ELEMENT_TYPE_IPV6:
104                 return "ipv6";
105         case CONNMAN_ELEMENT_TYPE_DHCP:
106                 return "dhcp";
107         case CONNMAN_ELEMENT_TYPE_BOOTP:
108                 return "bootp";
109         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
110                 return "zeroconf";
111         case CONNMAN_ELEMENT_TYPE_RESOLVER:
112                 return "resolver";
113         case CONNMAN_ELEMENT_TYPE_INTERNET:
114                 return "internet";
115         }
116
117         return NULL;
118 }
119
120 static const char *subtype2string(enum connman_element_subtype type)
121 {
122         switch (type) {
123         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
124                 return "unknown";
125         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
126                 return "ethernet";
127         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
128                 return "wifi";
129         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
130                 return "wimax";
131         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
132                 return "modem";
133         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
134                 return "bluetooth";
135         }
136
137         return NULL;
138 }
139
140 static void append_entry(DBusMessageIter *dict,
141                                 const char *key, int type, void *val)
142 {
143         DBusMessageIter entry, value;
144         const char *signature;
145
146         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
147                                                                 NULL, &entry);
148
149         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
150
151         switch (type) {
152         case DBUS_TYPE_BOOLEAN:
153                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
154                 break;
155         case DBUS_TYPE_STRING:
156                 signature = DBUS_TYPE_STRING_AS_STRING;
157                 break;
158         case DBUS_TYPE_UINT16:
159                 signature = DBUS_TYPE_UINT16_AS_STRING;
160                 break;
161         case DBUS_TYPE_UINT32:
162                 signature = DBUS_TYPE_UINT32_AS_STRING;
163                 break;
164         case DBUS_TYPE_OBJECT_PATH:
165                 signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
166                 break;
167         default:
168                 signature = DBUS_TYPE_VARIANT_AS_STRING;
169                 break;
170         }
171
172         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
173                                                         signature, &value);
174         dbus_message_iter_append_basic(&value, type, val);
175         dbus_message_iter_close_container(&entry, &value);
176
177         dbus_message_iter_close_container(dict, &entry);
178 }
179
180 static void append_property(DBusMessageIter *dict,
181                                 struct connman_property *property)
182 {
183         if (property->value == NULL)
184                 return;
185
186         append_entry(dict, property->name, property->type, &property->value);
187 }
188
189 static DBusMessage *get_properties(DBusConnection *conn,
190                                         DBusMessage *msg, void *data)
191 {
192         struct connman_element *element = data;
193         GSList *list;
194         DBusMessage *reply;
195         DBusMessageIter array, dict;
196         const char *str;
197
198         DBG("conn %p", conn);
199
200         reply = dbus_message_new_method_return(msg);
201         if (reply == NULL)
202                 return NULL;
203
204         dbus_message_iter_init_append(reply, &array);
205
206         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
207                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
208                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
209                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
210
211         if (element->parent != NULL &&
212                         element->parent->type != CONNMAN_ELEMENT_TYPE_ROOT) {
213                 append_entry(&dict, "Parent",
214                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
215         }
216
217         str = type2string(element->type);
218         if (str != NULL)
219                 append_entry(&dict, "Type", DBUS_TYPE_STRING, &str);
220         str = subtype2string(element->subtype);
221         if (str != NULL)
222                 append_entry(&dict, "Subtype", DBUS_TYPE_STRING, &str);
223
224         append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &element->enabled);
225
226         if (element->priority > 0)
227                 append_entry(&dict, "Priority",
228                                 DBUS_TYPE_UINT16, &element->priority);
229
230         if (element->network.identifier != NULL)
231                 append_entry(&dict, "Identifier",
232                                 DBUS_TYPE_STRING, &element->network.identifier);
233
234         if (element->ipv4.address != NULL)
235                 append_entry(&dict, "IPv4.Address",
236                                 DBUS_TYPE_STRING, &element->ipv4.address);
237         if (element->ipv4.netmask != NULL)
238                 append_entry(&dict, "IPv4.Netmask",
239                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
240         if (element->ipv4.gateway != NULL)
241                 append_entry(&dict, "IPv4.Gateway",
242                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
243
244         connman_element_lock(element);
245
246         for (list = element->properties; list; list = list->next) {
247                 struct connman_property *property = list->data;
248
249                 append_property(&dict, property);
250         }
251
252         connman_element_unlock(element);
253
254         dbus_message_iter_close_container(&array, &dict);
255
256         return reply;
257 }
258
259 static DBusMessage *set_property(DBusConnection *conn,
260                                         DBusMessage *msg, void *data)
261 {
262         struct connman_element *element = data;
263         DBusMessageIter iter;
264         DBusMessageIter value;
265         const char *name;
266         GSList *list;
267
268         DBG("conn %p", conn);
269
270         if (dbus_message_iter_init(msg, &iter) == FALSE)
271                 return __connman_error_invalid_arguments(msg);
272
273         dbus_message_iter_get_basic(&iter, &name);
274         dbus_message_iter_next(&iter);
275         dbus_message_iter_recurse(&iter, &value);
276
277         if (__connman_security_check_privileges(msg) < 0)
278                 return __connman_error_permission_denied(msg);
279
280         connman_element_lock(element);
281
282         for (list = element->properties; list; list = list->next) {
283                 struct connman_property *property = list->data;
284                 const char *str;
285
286                 if (g_str_equal(property->name, name) == FALSE)
287                         continue;
288
289                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
290                         continue;
291
292                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
293
294                 if (property->type == DBUS_TYPE_STRING) {
295                         dbus_message_iter_get_basic(&value, &str);
296                         g_free(property->value);
297                         property->value = g_strdup(str);
298                 } else
299                         property->value = NULL;
300         }
301
302         connman_element_unlock(element);
303
304         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
305 }
306
307 static DBusMessage *clear_property(DBusConnection *conn,
308                                         DBusMessage *msg, void *data)
309 {
310         struct connman_element *element = data;
311         const char *name;
312         GSList *list;
313
314         DBG("conn %p", conn);
315
316         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
317                                                 DBUS_TYPE_INVALID) == FALSE)
318                 return __connman_error_invalid_arguments(msg);
319
320         if (__connman_security_check_privileges(msg) < 0)
321                 return __connman_error_permission_denied(msg);
322
323         connman_element_lock(element);
324
325         for (list = element->properties; list; list = list->next) {
326                 struct connman_property *property = list->data;
327
328                 if (g_str_equal(property->name, name) == FALSE)
329                         continue;
330
331                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
332                         continue;
333
334                 if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)
335                         continue;
336
337                 property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE;
338
339                 if (property->type == DBUS_TYPE_STRING)
340                         g_free(property->value);
341
342                 property->value = NULL;
343         }
344
345         connman_element_unlock(element);
346
347         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
348 }
349
350 static DBusMessage *do_update(DBusConnection *conn,
351                                         DBusMessage *msg, void *data)
352 {
353         struct connman_element *element = data;
354
355         DBG("conn %p", conn);
356
357         if (element->driver == NULL)
358                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
359
360         if (element->driver->update) {
361                 DBG("Calling update callback");
362                 element->driver->update(element);
363         }
364
365         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
366 }
367
368 static DBusMessage *do_enable(DBusConnection *conn,
369                                         DBusMessage *msg, void *data)
370 {
371         struct connman_element *element = data;
372
373         DBG("conn %p", conn);
374
375         if (element->driver == NULL)
376                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
377
378         if (element->driver->enable) {
379                 DBG("Calling enable callback");
380                 element->driver->enable(element);
381         }
382
383         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
384 }
385
386 static DBusMessage *do_disable(DBusConnection *conn,
387                                         DBusMessage *msg, void *data)
388 {
389         struct connman_element *element = data;
390
391         DBG("conn %p", conn);
392
393         if (element->driver == NULL)
394                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
395
396         if (element->driver->disable) {
397                 DBG("Calling disable callback");
398                 element->driver->disable(element);
399         }
400
401         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
402 }
403
404 static GDBusMethodTable element_methods[] = {
405         { "GetProperties", "",   "a{sv}", get_properties },
406         { "SetProperty",   "sv", "",      set_property   },
407         { "ClearProperty", "s",  "",      clear_property },
408         { "Update",        "",   "",      do_update      },
409         { "Enable",        "",   "",      do_enable      },
410         { "Disable",       "",   "",      do_disable     },
411         { },
412 };
413
414 static GDBusSignalTable element_signals[] = {
415         { "PropertyChanged", "sv" },
416         { },
417 };
418
419 struct append_filter {
420         enum connman_element_type type;
421         DBusMessageIter *iter;
422 };
423
424 static gboolean append_path(GNode *node, gpointer data)
425 {
426         struct connman_element *element = node->data;
427         struct append_filter *filter = data;
428
429         DBG("element %p name %s", element, element->name);
430
431         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
432                 return FALSE;
433
434         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
435                                         filter->type != element->type)
436                 return FALSE;
437
438         dbus_message_iter_append_basic(filter->iter,
439                                 DBUS_TYPE_OBJECT_PATH, &element->path);
440
441         return FALSE;
442 }
443
444 void __connman_element_list(enum connman_element_type type,
445                                                 DBusMessageIter *iter)
446 {
447         struct append_filter filter = { type, iter };
448
449         DBG("");
450
451         g_static_rw_lock_reader_lock(&element_lock);
452         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
453                                                         append_path, &filter);
454         g_static_rw_lock_reader_unlock(&element_lock);
455 }
456
457 static gint compare_priority(gconstpointer a, gconstpointer b)
458 {
459         const struct connman_driver *driver1 = a;
460         const struct connman_driver *driver2 = b;
461
462         return driver2->priority - driver1->priority;
463 }
464
465 static gboolean match_driver(struct connman_element *element,
466                                         struct connman_driver *driver)
467 {
468         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
469                 return FALSE;
470
471         if (element->type != driver->type &&
472                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
473                 return FALSE;
474
475         if (element->subtype == driver->subtype ||
476                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
477                 return TRUE;
478
479         return FALSE;
480 }
481
482 static gboolean probe_driver(GNode *node, gpointer data)
483 {
484         struct connman_element *element = node->data;
485         struct connman_driver *driver = data;
486
487         DBG("element %p name %s", element, element->name);
488
489         if (!element->driver && match_driver(element, driver) == TRUE) {
490                 if (driver->probe(element) < 0)
491                         return FALSE;
492
493                 connman_element_lock(element);
494                 element->driver = driver;
495                 connman_element_unlock(element);
496         }
497
498         return FALSE;
499 }
500
501 /**
502  * connman_driver_register:
503  * @driver: driver definition
504  *
505  * Register a new driver
506  *
507  * Returns: %0 on success
508  */
509 int connman_driver_register(struct connman_driver *driver)
510 {
511         DBG("driver %p name %s", driver, driver->name);
512
513         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
514                 return -EINVAL;
515
516         if (!driver->probe)
517                 return -EINVAL;
518
519         g_static_rw_lock_writer_lock(&element_lock);
520
521         driver_list = g_slist_insert_sorted(driver_list, driver,
522                                                         compare_priority);
523
524         if (element_root != NULL)
525                 g_node_traverse(element_root, G_PRE_ORDER,
526                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
527
528         g_static_rw_lock_writer_unlock(&element_lock);
529
530         return 0;
531 }
532
533 static gboolean remove_driver(GNode *node, gpointer data)
534 {
535         struct connman_element *element = node->data;
536         struct connman_driver *driver = data;
537
538         DBG("element %p name %s", element, element->name);
539
540         if (element->driver == driver) {
541                 if (driver->remove)
542                         driver->remove(element);
543
544                 connman_element_lock(element);
545                 element->driver = NULL;
546                 connman_element_unlock(element);
547         }
548
549         return FALSE;
550 }
551
552 /**
553  * connman_driver_unregister:
554  * @driver: driver definition
555  *
556  * Remove a previously registered driver
557  */
558 void connman_driver_unregister(struct connman_driver *driver)
559 {
560         DBG("driver %p name %s", driver, driver->name);
561
562         g_static_rw_lock_writer_lock(&element_lock);
563
564         driver_list = g_slist_remove(driver_list, driver);
565
566         if (element_root != NULL)
567                 g_node_traverse(element_root, G_POST_ORDER,
568                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
569
570         g_static_rw_lock_writer_unlock(&element_lock);
571 }
572
573 /**
574  * connman_element_create:
575  * @name: element name
576  *
577  * Allocate a new element and assign the given #name to it. If the name
578  * is #NULL, it will be later on created based on the element type.
579  *
580  * Returns: a newly-allocated #connman_element structure
581  */
582 struct connman_element *connman_element_create(const char *name)
583 {
584         struct connman_element *element;
585
586         element = g_try_new0(struct connman_element, 1);
587         if (element == NULL)
588                 return NULL;
589
590         DBG("element %p", element);
591
592         element->refcount = 1;
593
594         g_static_mutex_init(&element->mutex);
595
596         element->name    = g_strdup(name);
597         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
598         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
599         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
600         element->index   = -1;
601         element->enabled = FALSE;
602
603         return element;
604 }
605
606 struct connman_element *connman_element_ref(struct connman_element *element)
607 {
608         DBG("element %p name %s refcount %d", element, element->name,
609                                 g_atomic_int_get(&element->refcount) + 1);
610
611         g_atomic_int_inc(&element->refcount);
612
613         return element;
614 }
615
616 static void free_properties(struct connman_element *element)
617 {
618         GSList *list;
619
620         DBG("element %p name %s", element, element->name);
621
622         connman_element_lock(element);
623
624         for (list = element->properties; list; list = list->next) {
625                 struct connman_property *property = list->data;
626
627                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) {
628                         if (property->type == DBUS_TYPE_STRING)
629                                 g_free(property->value);
630                 }
631
632                 g_free(property);
633         }
634
635         g_slist_free(element->properties);
636
637         element->properties = NULL;
638
639         connman_element_unlock(element);
640 }
641
642 void connman_element_unref(struct connman_element *element)
643 {
644         DBG("element %p name %s refcount %d", element, element->name,
645                                 g_atomic_int_get(&element->refcount) - 1);
646
647         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
648                 free_properties(element);
649                 g_free(element->ipv4.address);
650                 g_free(element->ipv4.netmask);
651                 g_free(element->ipv4.gateway);
652                 g_free(element->ipv4.network);
653                 g_free(element->ipv4.broadcast);
654                 g_free(element->ipv4.nameserver);
655                 g_free(element->network.identifier);
656                 g_free(element->path);
657                 g_free(element->name);
658                 g_free(element);
659         }
660 }
661
662 int connman_element_add_static_property(struct connman_element *element,
663                                 const char *name, int type, const void *value)
664 {
665         struct connman_property *property;
666
667         DBG("element %p name %s", element, element->name);
668
669         if (type != DBUS_TYPE_STRING)
670                 return -EINVAL;
671
672         property = g_try_new0(struct connman_property, 1);
673         if (property == NULL)
674                 return -ENOMEM;
675
676         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
677         property->id    = CONNMAN_PROPERTY_ID_INVALID;
678         property->name  = g_strdup(name);
679         property->type  = type;
680
681         DBG("name %s type %d value %p", name, type, value);
682
683         switch (type) {
684         case DBUS_TYPE_STRING:
685                 property->value = g_strdup(*((const char **) value));
686                 break;
687         }
688
689         connman_element_lock(element);
690         element->properties = g_slist_append(element->properties, property);
691         connman_element_unlock(element);
692
693         return 0;
694 }
695
696 static void *get_reference_value(struct connman_element *element,
697                                                 enum connman_property_id id)
698 {
699         GSList *list;
700
701         DBG("element %p name %s", element, element->name);
702
703         for (list = element->properties; list; list = list->next) {
704                 struct connman_property *property = list->data;
705
706                 if (property->id != id)
707                         continue;
708
709                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
710                         return property->value;
711         }
712
713         if (element->parent == NULL)
714                 return NULL;
715
716         return get_reference_value(element->parent, id);
717 }
718
719 static void set_reference_properties(struct connman_element *element)
720 {
721         GSList *list;
722
723         DBG("element %p name %s", element, element->name);
724
725         for (list = element->properties; list; list = list->next) {
726                 struct connman_property *property = list->data;
727
728                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
729                         continue;
730
731                 property->value = get_reference_value(element->parent,
732                                                                 property->id);
733         }
734 }
735
736 static struct connman_property *create_property(struct connman_element *element,
737                                                 enum connman_property_id id)
738 {
739         struct connman_property *property;
740         GSList *list;
741
742         DBG("element %p name %s", element, element->name);
743
744         connman_element_lock(element);
745
746         for (list = element->properties; list; list = list->next) {
747                 property = list->data;
748
749                 if (property->id == id)
750                         goto unlock;
751         }
752
753         property = g_try_new0(struct connman_property, 1);
754         if (property == NULL)
755                 goto unlock;
756
757         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
758         property->id    = id;
759         property->name  = g_strdup(propid2name(id));
760         property->type  = propid2type(id);
761
762         if (property->name == NULL) {
763                 g_free(property);
764                 property = NULL;
765                 goto unlock;
766         }
767
768         element->properties = g_slist_append(element->properties, property);
769
770 unlock:
771         connman_element_unlock(element);
772
773         return property;
774 }
775
776 static void create_default_properties(struct connman_element *element)
777 {
778         struct connman_property *property;
779         int i;
780
781         DBG("element %p name %s", element, element->name);
782
783         for (i = 0; propid_table[i].name; i++) {
784                 DBG("property %s", propid_table[i].name);
785
786                 property = create_property(element, propid_table[i].id);
787
788                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
789
790                 if (propid_table[i].type != DBUS_TYPE_STRING)
791                         continue;
792
793                 if (propid_table[i].value)
794                         property->value = g_strdup(propid_table[i].value);
795                 else
796                         property->value = g_strdup("");
797         }
798 }
799
800 static int define_properties_valist(struct connman_element *element,
801                                                                 va_list args)
802 {
803         enum connman_property_id id;
804
805         DBG("element %p name %s", element, element->name);
806
807         id = va_arg(args, enum connman_property_id);
808
809         while (id != CONNMAN_PROPERTY_ID_INVALID) {
810
811                 DBG("property %d", id);
812
813                 create_property(element, id);
814
815                 id = va_arg(args, enum connman_property_id);
816         }
817
818         return 0;
819 }
820
821 /**
822  * connman_element_define_properties:
823  * @element: an element
824  * @varargs: list of property identifiers
825  *
826  * Define the valid properties for an element.
827  *
828  * Returns: %0 on success
829  */
830 int connman_element_define_properties(struct connman_element *element, ...)
831 {
832         va_list args;
833         int err;
834
835         DBG("element %p name %s", element, element->name);
836
837         va_start(args, element);
838
839         err = define_properties_valist(element, args);
840
841         va_end(args);
842
843         return err;
844 }
845
846 int connman_element_create_property(struct connman_element *element,
847                                                 const char *name, int type)
848 {
849         return -EIO;
850 }
851
852 int connman_element_set_property(struct connman_element *element,
853                                 enum connman_property_id id, const void *value)
854 {
855 #if 0
856         switch (type) {
857         case CONNMAN_PROPERTY_TYPE_INVALID:
858                 return -EINVAL;
859         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
860                 connman_element_lock(element);
861                 g_free(element->ipv4.address);
862                 element->ipv4.address = g_strdup(*((const char **) value));
863                 connman_element_unlock(element);
864                 break;
865         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
866                 connman_element_lock(element);
867                 g_free(element->ipv4.netmask);
868                 element->ipv4.netmask = g_strdup(*((const char **) value));
869                 connman_element_unlock(element);
870                 break;
871         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
872                 connman_element_lock(element);
873                 g_free(element->ipv4.gateway);
874                 element->ipv4.gateway = g_strdup(*((const char **) value));
875                 connman_element_unlock(element);
876                 break;
877         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
878                 connman_element_lock(element);
879                 g_free(element->ipv4.nameserver);
880                 element->ipv4.nameserver = g_strdup(*((const char **) value));
881                 connman_element_unlock(element);
882                 break;
883         }
884 #endif
885
886         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
887                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
888                                 DBUS_TYPE_OBJECT_PATH, &element->path,
889                                                         DBUS_TYPE_INVALID);
890
891         return 0;
892 }
893
894 int connman_element_get_value(struct connman_element *element,
895                                 enum connman_property_id id, void *value)
896 {
897         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
898                 return -EINVAL;
899
900 #if 0
901         switch (type) {
902         case CONNMAN_PROPERTY_TYPE_INVALID:
903                 return -EINVAL;
904         case CONNMAN_PROPERTY_TYPE_IPV4_ADDRESS:
905                 if (element->ipv4.address == NULL)
906                         return connman_element_get_value(element->parent,
907                                                                 type, value);
908                 connman_element_lock(element);
909                 *((char **) value) = element->ipv4.address;
910                 connman_element_unlock(element);
911                 break;
912         case CONNMAN_PROPERTY_TYPE_IPV4_NETMASK:
913                 if (element->ipv4.netmask == NULL)
914                         return connman_element_get_value(element->parent,
915                                                                 type, value);
916                 connman_element_lock(element);
917                 *((char **) value) = element->ipv4.netmask;
918                 connman_element_unlock(element);
919                 break;
920         case CONNMAN_PROPERTY_TYPE_IPV4_GATEWAY:
921                 if (element->ipv4.gateway == NULL)
922                         return connman_element_get_value(element->parent,
923                                                                 type, value);
924                 connman_element_lock(element);
925                 *((char **) value) = element->ipv4.gateway;
926                 connman_element_unlock(element);
927                 break;
928         case CONNMAN_PROPERTY_TYPE_IPV4_NAMESERVER:
929                 if (element->ipv4.nameserver == NULL)
930                         return connman_element_get_value(element->parent,
931                                                                 type, value);
932                 connman_element_lock(element);
933                 *((char **) value) = element->ipv4.nameserver;
934                 connman_element_unlock(element);
935                 break;
936         }
937 #endif
938
939         return 0;
940 }
941
942 /**
943  * connman_element_register:
944  * @element: the element to register
945  * @parent: the parent to register the element with
946  *
947  * Register an element with the core. It will be register under the given
948  * parent of if %NULL is provided under the root element.
949  *
950  * Returns: %0 on success
951  */
952 int connman_element_register(struct connman_element *element,
953                                         struct connman_element *parent)
954 {
955         DBG("element %p name %s parent %p", element, element->name, parent);
956
957         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
958                 if (g_str_equal(device_filter, element->name) == FALSE)
959                         return -EPERM;
960         }
961
962         if (connman_element_ref(element) == NULL)
963                 return -EINVAL;
964
965         connman_element_lock(element);
966
967         __connman_element_load(element);
968
969         if (element->name == NULL) {
970                 element->name = g_strdup(type2string(element->type));
971                 if (element->name == NULL) {
972                         connman_element_unlock(element);
973                         return -EINVAL;
974                 }
975         }
976
977         element->parent = parent;
978
979         connman_element_unlock(element);
980
981         if (thread_register != NULL)
982                 g_thread_pool_push(thread_register, element, NULL);
983
984         return 0;
985 }
986
987 void connman_element_unregister(struct connman_element *element)
988 {
989         DBG("element %p name %s", element, element->name);
990
991         if (thread_unregister != NULL)
992                 g_thread_pool_push(thread_unregister, element, NULL);
993 }
994
995 void connman_element_unregister_children(struct connman_element *element)
996 {
997         DBG("element %p name %s", element, element->name);
998
999         if (thread_unregister_children != NULL)
1000                 g_thread_pool_push(thread_unregister_children, element, NULL);
1001 }
1002
1003 static gboolean update_element(GNode *node, gpointer user_data)
1004 {
1005         struct connman_element *element = node->data;
1006
1007         DBG("element %p name %s", element, element->name);
1008
1009         if (element->driver && element->driver->update)
1010                 element->driver->update(element);
1011
1012         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1013                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1014                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1015                                                         DBUS_TYPE_INVALID);
1016
1017         return FALSE;
1018 }
1019
1020 void connman_element_update(struct connman_element *element)
1021 {
1022         GNode *node;
1023
1024         DBG("element %p name %s", element, element->name);
1025
1026         g_static_rw_lock_reader_lock(&element_lock);
1027
1028         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1029
1030         if (node != NULL)
1031                 g_node_traverse(node, G_PRE_ORDER,
1032                                 G_TRAVERSE_ALL, -1, update_element, NULL);
1033
1034         g_static_rw_lock_reader_unlock(&element_lock);
1035 }
1036
1037 static void register_element(gpointer data, gpointer user_data)
1038 {
1039         struct connman_element *element = data;
1040         const gchar *basepath;
1041         GSList *list;
1042         GNode *node;
1043
1044         g_static_rw_lock_writer_lock(&element_lock);
1045
1046         connman_element_lock(element);
1047
1048         if (element->parent) {
1049                 node = g_node_find(element_root, G_PRE_ORDER,
1050                                         G_TRAVERSE_ALL, element->parent);
1051                 basepath = element->parent->path;
1052
1053                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1054                         element->subtype = element->parent->subtype;
1055         } else {
1056                 element->parent = element_root->data;
1057
1058                 node = element_root;
1059                 basepath = "";
1060         }
1061
1062         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1063
1064         set_reference_properties(element);
1065
1066         connman_element_unlock(element);
1067
1068         DBG("element %p path %s", element, element->path);
1069
1070         g_node_append_data(node, element);
1071
1072         if (g_dbus_register_interface(connection, element->path,
1073                                         CONNMAN_ELEMENT_INTERFACE,
1074                                         element_methods, element_signals,
1075                                         NULL, element, NULL) == FALSE)
1076                 connman_error("Failed to register %s", element->path);
1077
1078         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1079                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
1080                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1081                                                         DBUS_TYPE_INVALID);
1082
1083         g_static_rw_lock_writer_unlock(&element_lock);
1084
1085         __connman_element_store(element);
1086
1087         g_static_rw_lock_writer_lock(&element_lock);
1088
1089         for (list = driver_list; list; list = list->next) {
1090                 struct connman_driver *driver = list->data;
1091
1092                 if (match_driver(element, driver) == FALSE)
1093                         continue;
1094
1095                 DBG("driver %p name %s", driver, driver->name);
1096
1097                 if (driver->probe(element) == 0) {
1098                         connman_element_lock(element);
1099                         element->driver = driver;
1100                         connman_element_unlock(element);
1101                         break;
1102                 }
1103         }
1104
1105         g_static_rw_lock_writer_unlock(&element_lock);
1106 }
1107
1108 static gboolean remove_element(GNode *node, gpointer user_data)
1109 {
1110         struct connman_element *element = node->data;
1111         struct connman_element *root = user_data;
1112
1113         DBG("element %p name %s", element, element->name);
1114
1115         if (element == root)
1116                 return FALSE;
1117
1118         if (element->driver) {
1119                 if (element->driver->remove)
1120                         element->driver->remove(element);
1121
1122                 connman_element_lock(element);
1123                 element->driver = NULL;
1124                 connman_element_unlock(element);
1125         }
1126
1127         if (node != NULL) {
1128                 g_node_unlink(node);
1129                 g_node_destroy(node);
1130         }
1131
1132         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1133                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
1134                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1135                                                         DBUS_TYPE_INVALID);
1136
1137         g_dbus_unregister_interface(connection, element->path,
1138                                                 CONNMAN_ELEMENT_INTERFACE);
1139
1140         connman_element_unref(element);
1141
1142         return FALSE;
1143 }
1144
1145 static void unregister_element(gpointer data, gpointer user_data)
1146 {
1147         struct connman_element *element = data;
1148         GNode *node;
1149
1150         DBG("element %p name %s", element, element->name);
1151
1152         g_static_rw_lock_writer_lock(&element_lock);
1153
1154         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1155
1156         if (node != NULL)
1157                 g_node_traverse(node, G_POST_ORDER,
1158                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1159
1160         g_static_rw_lock_writer_unlock(&element_lock);
1161 }
1162
1163 static void unregister_children(gpointer data, gpointer user_data)
1164 {
1165         struct connman_element *element = data;
1166         GNode *node;
1167
1168         DBG("element %p name %s", element, element->name);
1169
1170         g_static_rw_lock_writer_lock(&element_lock);
1171
1172         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1173
1174         if (node != NULL)
1175                 g_node_traverse(node, G_POST_ORDER,
1176                                 G_TRAVERSE_ALL, -1, remove_element, element);
1177
1178         g_static_rw_lock_writer_unlock(&element_lock);
1179 }
1180
1181 int __connman_element_init(DBusConnection *conn, const char *device)
1182 {
1183         struct connman_element *element;
1184
1185         DBG("conn %p", conn);
1186
1187         connection = dbus_connection_ref(conn);
1188         if (connection == NULL)
1189                 return -EIO;
1190
1191         device_filter = g_strdup(device);
1192
1193         g_static_rw_lock_writer_lock(&element_lock);
1194
1195         element = connman_element_create("root");
1196
1197         element->path = g_strdup("/");
1198         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1199
1200         create_default_properties(element);
1201
1202         element_root = g_node_new(element);
1203
1204         g_static_rw_lock_writer_unlock(&element_lock);
1205
1206         thread_register = g_thread_pool_new(register_element,
1207                                                         NULL, 1, FALSE, NULL);
1208         thread_unregister = g_thread_pool_new(unregister_element,
1209                                                         NULL, 1, FALSE, NULL);
1210         thread_unregister_children = g_thread_pool_new(unregister_children,
1211                                                         NULL, 1, FALSE, NULL);
1212
1213         return 0;
1214 }
1215
1216 static gboolean free_driver(GNode *node, gpointer data)
1217 {
1218         struct connman_element *element = node->data;
1219
1220         DBG("element %p name %s", element, element->name);
1221
1222         if (element->driver) {
1223                 if (element->driver->remove)
1224                         element->driver->remove(element);
1225
1226                 connman_element_lock(element);
1227                 element->driver = NULL;
1228                 connman_element_unlock(element);
1229         }
1230
1231         return FALSE;
1232 }
1233
1234 static gboolean free_node(GNode *node, gpointer data)
1235 {
1236         struct connman_element *element = node->data;
1237
1238         DBG("element %p name %s", element, element->name);
1239
1240         if (g_node_depth(node) > 1)
1241                 g_thread_pool_push(thread_unregister, element, NULL);
1242
1243         return FALSE;
1244 }
1245
1246 void __connman_element_cleanup(void)
1247 {
1248         DBG("");
1249
1250         g_thread_pool_free(thread_register, TRUE, TRUE);
1251         thread_register = NULL;
1252
1253         g_static_rw_lock_writer_lock(&element_lock);
1254         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1255                                                         free_driver, NULL);
1256         g_static_rw_lock_writer_unlock(&element_lock);
1257
1258         g_static_rw_lock_writer_lock(&element_lock);
1259         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1260                                                         free_node, NULL);
1261         g_static_rw_lock_writer_unlock(&element_lock);
1262
1263         g_thread_pool_free(thread_unregister, FALSE, TRUE);
1264         thread_unregister = NULL;
1265
1266         g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
1267         thread_unregister_children = NULL;
1268
1269         g_static_rw_lock_writer_lock(&element_lock);
1270         g_node_destroy(element_root);
1271         element_root = NULL;
1272         g_static_rw_lock_writer_unlock(&element_lock);
1273
1274         g_free(device_filter);
1275
1276         dbus_connection_unref(connection);
1277 }