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