3e2e0c3ebe44c81ddea12c30dae4c7d77e9d291e
[framework/connectivity/connman.git] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 static DBusConnection *connection;
36
37 static GStaticRWLock element_lock = G_STATIC_RW_LOCK_INIT;
38 static GNode *element_root = NULL;
39
40 static GSList *driver_list = NULL;
41
42 static GThreadPool *thread_register = NULL;
43 static GThreadPool *thread_unregister = NULL;
44 static GThreadPool *thread_unregister_children = NULL;
45
46 static gchar *device_filter = NULL;
47
48 static struct {
49         enum connman_property_id id;
50         int type;
51         const char *name;
52         const void *value;
53 } propid_table[] = {
54         { CONNMAN_PROPERTY_ID_IPV4_METHOD,
55                 DBUS_TYPE_STRING, "IPv4.Method", "dhcp" },
56         { CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
57                 DBUS_TYPE_STRING, "IPv4.Address" },
58         { CONNMAN_PROPERTY_ID_IPV4_NETMASK,
59                 DBUS_TYPE_STRING, "IPv4.Netmask" },
60         { CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
61                 DBUS_TYPE_STRING, "IPv4.Gateway" },
62         { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
63                 DBUS_TYPE_STRING, "IPv4.Nameserver" },
64
65         { CONNMAN_PROPERTY_ID_WIFI_SECURITY,
66                 DBUS_TYPE_STRING, "WiFi.Security" },
67         { CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE,
68                 DBUS_TYPE_STRING, "WiFi.Passphrase" },
69
70         { }
71 };
72
73 static int propid2type(enum connman_property_id id)
74 {
75         int i;
76
77         for (i = 0; propid_table[i].name; i++) {
78                 if (propid_table[i].id == id)
79                         return propid_table[i].type;
80         }
81
82         return DBUS_TYPE_INVALID;
83 }
84
85 static const char *propid2name(enum connman_property_id id)
86 {
87         int i;
88
89         for (i = 0; propid_table[i].name; i++) {
90                 if (propid_table[i].id == id)
91                         return propid_table[i].name;
92         }
93
94         return NULL;
95 }
96
97 static const char *type2string(enum connman_element_type type)
98 {
99         switch (type) {
100         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
101                 return "unknown";
102         case CONNMAN_ELEMENT_TYPE_ROOT:
103                 return "root";
104         case CONNMAN_ELEMENT_TYPE_PROFILE:
105                 return "profile";
106         case CONNMAN_ELEMENT_TYPE_DEVICE:
107                 return "device";
108         case CONNMAN_ELEMENT_TYPE_NETWORK:
109                 return "network";
110         case CONNMAN_ELEMENT_TYPE_IPV4:
111                 return "ipv4";
112         case CONNMAN_ELEMENT_TYPE_IPV6:
113                 return "ipv6";
114         case CONNMAN_ELEMENT_TYPE_DHCP:
115                 return "dhcp";
116         case CONNMAN_ELEMENT_TYPE_BOOTP:
117                 return "bootp";
118         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
119                 return "zeroconf";
120         case CONNMAN_ELEMENT_TYPE_RESOLVER:
121                 return "resolver";
122         case CONNMAN_ELEMENT_TYPE_INTERNET:
123                 return "internet";
124         }
125
126         return NULL;
127 }
128
129 static const char *subtype2string(enum connman_element_subtype type)
130 {
131         switch (type) {
132         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
133                 return "unknown";
134         case CONNMAN_ELEMENT_SUBTYPE_FAKE:
135                 return "fake";
136         case CONNMAN_ELEMENT_SUBTYPE_NETWORK:
137                 return "network";
138         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
139                 return "ethernet";
140         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
141                 return "wifi";
142         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
143                 return "wimax";
144         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
145                 return "modem";
146         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
147                 return "bluetooth";
148         }
149
150         return NULL;
151 }
152
153 static void append_property(DBusMessageIter *dict,
154                                 struct connman_property *property)
155 {
156         if (property->value == NULL)
157                 return;
158
159         if (property->type == DBUS_TYPE_ARRAY)
160                 connman_dbus_dict_append_array(dict, property->name,
161                         property->subtype, &property->value, property->size);
162         else
163                 connman_dbus_dict_append_variant(dict, property->name,
164                                         property->type, &property->value);
165 }
166
167 static DBusMessage *get_properties(DBusConnection *conn,
168                                         DBusMessage *msg, void *data)
169 {
170         struct connman_element *element = data;
171         GSList *list;
172         DBusMessage *reply;
173         DBusMessageIter array, dict;
174         const char *str;
175
176         DBG("conn %p", conn);
177
178         reply = dbus_message_new_method_return(msg);
179         if (reply == NULL)
180                 return NULL;
181
182         dbus_message_iter_init_append(reply, &array);
183
184         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
185                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
186                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
187                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
188
189         if (element->parent != NULL &&
190                         element->parent->type != CONNMAN_ELEMENT_TYPE_ROOT) {
191                 connman_dbus_dict_append_variant(&dict, "Parent",
192                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
193         }
194
195         str = type2string(element->type);
196         if (str != NULL)
197                 connman_dbus_dict_append_variant(&dict, "Type",
198                                                 DBUS_TYPE_STRING, &str);
199         str = subtype2string(element->subtype);
200         if (str != NULL)
201                 connman_dbus_dict_append_variant(&dict, "Subtype",
202                                                 DBUS_TYPE_STRING, &str);
203
204         connman_dbus_dict_append_variant(&dict, "Enabled",
205                                         DBUS_TYPE_BOOLEAN, &element->enabled);
206
207         if (element->priority > 0)
208                 connman_dbus_dict_append_variant(&dict, "Priority",
209                                         DBUS_TYPE_UINT16, &element->priority);
210
211         if (element->ipv4.address != NULL)
212                 connman_dbus_dict_append_variant(&dict, "IPv4.Address",
213                                 DBUS_TYPE_STRING, &element->ipv4.address);
214         if (element->ipv4.netmask != NULL)
215                 connman_dbus_dict_append_variant(&dict, "IPv4.Netmask",
216                                 DBUS_TYPE_STRING, &element->ipv4.netmask);
217         if (element->ipv4.gateway != NULL)
218                 connman_dbus_dict_append_variant(&dict, "IPv4.Gateway",
219                                 DBUS_TYPE_STRING, &element->ipv4.gateway);
220
221         if (element->wifi.security != NULL)
222                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
223                                 DBUS_TYPE_STRING, &element->wifi.security);
224         if (element->wifi.passphrase != NULL)
225                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
226                                 DBUS_TYPE_STRING, &element->wifi.passphrase);
227
228         connman_element_lock(element);
229
230         for (list = element->properties; list; list = list->next) {
231                 struct connman_property *property = list->data;
232
233                 append_property(&dict, property);
234         }
235
236         connman_element_unlock(element);
237
238         dbus_message_iter_close_container(&array, &dict);
239
240         return reply;
241 }
242
243 static DBusMessage *set_property(DBusConnection *conn,
244                                         DBusMessage *msg, void *data)
245 {
246         struct connman_element *element = data;
247         DBusMessageIter iter;
248         DBusMessageIter value;
249         const char *name;
250         GSList *list;
251
252         DBG("conn %p", conn);
253
254         if (dbus_message_iter_init(msg, &iter) == FALSE)
255                 return __connman_error_invalid_arguments(msg);
256
257         dbus_message_iter_get_basic(&iter, &name);
258         dbus_message_iter_next(&iter);
259         dbus_message_iter_recurse(&iter, &value);
260
261         if (__connman_security_check_privileges(msg) < 0)
262                 return __connman_error_permission_denied(msg);
263
264         connman_element_lock(element);
265
266         for (list = element->properties; list; list = list->next) {
267                 struct connman_property *property = list->data;
268                 const char *str;
269
270                 if (g_str_equal(property->name, name) == FALSE)
271                         continue;
272
273                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
274                         continue;
275
276                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
277
278                 if (property->type == DBUS_TYPE_STRING) {
279                         dbus_message_iter_get_basic(&value, &str);
280                         g_free(property->value);
281                         property->value = g_strdup(str);
282                 } else
283                         property->value = NULL;
284         }
285
286         connman_element_unlock(element);
287
288         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
289 }
290
291 static DBusMessage *clear_property(DBusConnection *conn,
292                                         DBusMessage *msg, void *data)
293 {
294         struct connman_element *element = data;
295         const char *name;
296         GSList *list;
297
298         DBG("conn %p", conn);
299
300         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
301                                                 DBUS_TYPE_INVALID) == FALSE)
302                 return __connman_error_invalid_arguments(msg);
303
304         if (__connman_security_check_privileges(msg) < 0)
305                 return __connman_error_permission_denied(msg);
306
307         connman_element_lock(element);
308
309         for (list = element->properties; list; list = list->next) {
310                 struct connman_property *property = list->data;
311
312                 if (g_str_equal(property->name, name) == FALSE)
313                         continue;
314
315                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
316                         continue;
317
318                 if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)
319                         continue;
320
321                 property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE;
322
323                 if (property->type == DBUS_TYPE_STRING)
324                         g_free(property->value);
325
326                 property->value = NULL;
327         }
328
329         connman_element_unlock(element);
330
331         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
332 }
333
334 static DBusMessage *do_update(DBusConnection *conn,
335                                         DBusMessage *msg, void *data)
336 {
337         struct connman_element *element = data;
338
339         DBG("conn %p", conn);
340
341         if (element->enabled == FALSE)
342                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
343
344         if (element->driver && element->driver->update) {
345                 DBG("Calling update callback");
346                 element->driver->update(element);
347         }
348
349         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
350 }
351
352 static DBusMessage *do_enable(DBusConnection *conn,
353                                         DBusMessage *msg, void *data)
354 {
355         struct connman_element *element = data;
356
357         DBG("conn %p", conn);
358
359         if (element->enabled == TRUE)
360                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
361
362         if (element->driver && element->driver->enable) {
363                 DBG("Calling enable callback");
364                 if (element->driver->enable(element) < 0)
365                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
366         }
367
368         element->enabled = TRUE;
369
370         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
371                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
372                                 DBUS_TYPE_OBJECT_PATH, &element->path,
373                                                         DBUS_TYPE_INVALID);
374
375         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
376 }
377
378 static DBusMessage *do_disable(DBusConnection *conn,
379                                         DBusMessage *msg, void *data)
380 {
381         struct connman_element *element = data;
382
383         DBG("conn %p", conn);
384
385         if (element->enabled == FALSE)
386                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
387
388         if (element->driver && element->driver->disable) {
389                 DBG("Calling disable callback");
390                 if (element->driver->disable(element) < 0)
391                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
392         }
393
394         element->enabled = FALSE;
395
396         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
397                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
398                                 DBUS_TYPE_OBJECT_PATH, &element->path,
399                                                         DBUS_TYPE_INVALID);
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 void __connman_driver_rescan(struct connman_driver *driver)
502 {
503         DBG("driver %p name %s", driver, driver->name);
504
505         if (!driver->probe)
506                 return;
507
508         g_static_rw_lock_writer_lock(&element_lock);
509
510         if (element_root != NULL)
511                 g_node_traverse(element_root, G_PRE_ORDER,
512                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
513
514         g_static_rw_lock_writer_unlock(&element_lock);
515 }
516
517 /**
518  * connman_driver_register:
519  * @driver: driver definition
520  *
521  * Register a new driver
522  *
523  * Returns: %0 on success
524  */
525 int connman_driver_register(struct connman_driver *driver)
526 {
527         DBG("driver %p name %s", driver, driver->name);
528
529         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
530                 return -EINVAL;
531
532         if (!driver->probe)
533                 return -EINVAL;
534
535         g_static_rw_lock_writer_lock(&element_lock);
536
537         driver_list = g_slist_insert_sorted(driver_list, driver,
538                                                         compare_priority);
539
540         if (element_root != NULL)
541                 g_node_traverse(element_root, G_PRE_ORDER,
542                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
543
544         g_static_rw_lock_writer_unlock(&element_lock);
545
546         return 0;
547 }
548
549 static gboolean remove_driver(GNode *node, gpointer data)
550 {
551         struct connman_element *element = node->data;
552         struct connman_driver *driver = data;
553
554         DBG("element %p name %s", element, element->name);
555
556         if (element->driver == driver) {
557                 if (driver->remove)
558                         driver->remove(element);
559
560                 connman_element_lock(element);
561                 element->driver = NULL;
562                 connman_element_unlock(element);
563         }
564
565         return FALSE;
566 }
567
568 /**
569  * connman_driver_unregister:
570  * @driver: driver definition
571  *
572  * Remove a previously registered driver
573  */
574 void connman_driver_unregister(struct connman_driver *driver)
575 {
576         DBG("driver %p name %s", driver, driver->name);
577
578         g_static_rw_lock_writer_lock(&element_lock);
579
580         driver_list = g_slist_remove(driver_list, driver);
581
582         if (element_root != NULL)
583                 g_node_traverse(element_root, G_POST_ORDER,
584                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
585
586         g_static_rw_lock_writer_unlock(&element_lock);
587 }
588
589 /**
590  * connman_element_create:
591  * @name: element name
592  *
593  * Allocate a new element and assign the given #name to it. If the name
594  * is #NULL, it will be later on created based on the element type.
595  *
596  * Returns: a newly-allocated #connman_element structure
597  */
598 struct connman_element *connman_element_create(const char *name)
599 {
600         struct connman_element *element;
601
602         element = g_try_new0(struct connman_element, 1);
603         if (element == NULL)
604                 return NULL;
605
606         DBG("element %p", element);
607
608         element->refcount = 1;
609
610         g_static_mutex_init(&element->mutex);
611
612         element->name    = g_strdup(name);
613         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
614         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
615         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
616         element->index   = -1;
617         element->enabled = FALSE;
618
619         return element;
620 }
621
622 struct connman_element *connman_element_ref(struct connman_element *element)
623 {
624         DBG("element %p name %s refcount %d", element, element->name,
625                                 g_atomic_int_get(&element->refcount) + 1);
626
627         g_atomic_int_inc(&element->refcount);
628
629         return element;
630 }
631
632 static void free_properties(struct connman_element *element)
633 {
634         GSList *list;
635
636         DBG("element %p name %s", element, element->name);
637
638         connman_element_lock(element);
639
640         for (list = element->properties; list; list = list->next) {
641                 struct connman_property *property = list->data;
642
643                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)) {
644                         if (property->type == DBUS_TYPE_STRING)
645                                 g_free(property->value);
646                         if (property->type == DBUS_TYPE_ARRAY &&
647                                         property->subtype == DBUS_TYPE_BYTE)
648                                 g_free(property->value);
649                 }
650
651                 g_free(property);
652         }
653
654         g_slist_free(element->properties);
655
656         element->properties = NULL;
657
658         connman_element_unlock(element);
659 }
660
661 void connman_element_unref(struct connman_element *element)
662 {
663         DBG("element %p name %s refcount %d", element, element->name,
664                                 g_atomic_int_get(&element->refcount) - 1);
665
666         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
667                 free_properties(element);
668                 g_free(element->ipv4.address);
669                 g_free(element->ipv4.netmask);
670                 g_free(element->ipv4.gateway);
671                 g_free(element->ipv4.network);
672                 g_free(element->ipv4.broadcast);
673                 g_free(element->ipv4.nameserver);
674                 g_free(element->path);
675                 g_free(element->name);
676                 g_free(element);
677         }
678 }
679
680 int connman_element_add_static_property(struct connman_element *element,
681                                 const char *name, int type, const void *value)
682 {
683         struct connman_property *property;
684
685         DBG("element %p name %s", element, element->name);
686
687         if (type != DBUS_TYPE_STRING)
688                 return -EINVAL;
689
690         property = g_try_new0(struct connman_property, 1);
691         if (property == NULL)
692                 return -ENOMEM;
693
694         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
695         property->id    = CONNMAN_PROPERTY_ID_INVALID;
696         property->name  = g_strdup(name);
697         property->type  = type;
698
699         DBG("name %s type %d value %p", name, type, value);
700
701         switch (type) {
702         case DBUS_TYPE_STRING:
703                 property->value = g_strdup(*((const char **) value));
704                 break;
705         }
706
707         connman_element_lock(element);
708         element->properties = g_slist_append(element->properties, property);
709         connman_element_unlock(element);
710
711         return 0;
712 }
713
714 int connman_element_add_static_array_property(struct connman_element *element,
715                         const char *name, int type, const void *value, int len)
716 {
717         struct connman_property *property;
718
719         DBG("element %p name %s", element, element->name);
720
721         if (type != DBUS_TYPE_BYTE)
722                 return -EINVAL;
723
724         property = g_try_new0(struct connman_property, 1);
725         if (property == NULL)
726                 return -ENOMEM;
727
728         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
729         property->id      = CONNMAN_PROPERTY_ID_INVALID;
730         property->name    = g_strdup(name);
731         property->type    = DBUS_TYPE_ARRAY;
732         property->subtype = type;
733
734         DBG("name %s type %d value %p", name, type, value);
735
736         switch (type) {
737         case DBUS_TYPE_BYTE:
738                 property->value = g_try_malloc(len);
739                 if (property->value != NULL) {
740                         memcpy(property->value,
741                                 *((const unsigned char **) value), len);
742                         property->size = len;
743                 }
744                 break;
745         }
746
747         connman_element_lock(element);
748         element->properties = g_slist_append(element->properties, property);
749         connman_element_unlock(element);
750
751         return 0;
752 }
753
754 static void *get_reference_value(struct connman_element *element,
755                                                 enum connman_property_id id)
756 {
757         GSList *list;
758
759         DBG("element %p name %s", element, element->name);
760
761         for (list = element->properties; list; list = list->next) {
762                 struct connman_property *property = list->data;
763
764                 if (property->id != id)
765                         continue;
766
767                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
768                         return property->value;
769         }
770
771         if (element->parent == NULL)
772                 return NULL;
773
774         return get_reference_value(element->parent, id);
775 }
776
777 static void set_reference_properties(struct connman_element *element)
778 {
779         GSList *list;
780
781         DBG("element %p name %s", element, element->name);
782
783         for (list = element->properties; list; list = list->next) {
784                 struct connman_property *property = list->data;
785
786                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
787                         continue;
788
789                 property->value = get_reference_value(element->parent,
790                                                                 property->id);
791         }
792 }
793
794 static struct connman_property *create_property(struct connman_element *element,
795                                                 enum connman_property_id id)
796 {
797         struct connman_property *property;
798         GSList *list;
799
800         DBG("element %p name %s", element, element->name);
801
802         connman_element_lock(element);
803
804         for (list = element->properties; list; list = list->next) {
805                 property = list->data;
806
807                 if (property->id == id)
808                         goto unlock;
809         }
810
811         property = g_try_new0(struct connman_property, 1);
812         if (property == NULL)
813                 goto unlock;
814
815         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
816         property->id    = id;
817         property->name  = g_strdup(propid2name(id));
818         property->type  = propid2type(id);
819
820         if (property->name == NULL) {
821                 g_free(property);
822                 property = NULL;
823                 goto unlock;
824         }
825
826         element->properties = g_slist_append(element->properties, property);
827
828 unlock:
829         connman_element_unlock(element);
830
831         return property;
832 }
833
834 static void create_default_properties(struct connman_element *element)
835 {
836         struct connman_property *property;
837         int i;
838
839         DBG("element %p name %s", element, element->name);
840
841         for (i = 0; propid_table[i].name; i++) {
842                 DBG("property %s", propid_table[i].name);
843
844                 property = create_property(element, propid_table[i].id);
845
846                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
847
848                 if (propid_table[i].type != DBUS_TYPE_STRING)
849                         continue;
850
851                 if (propid_table[i].value)
852                         property->value = g_strdup(propid_table[i].value);
853                 else
854                         property->value = g_strdup("");
855         }
856 }
857
858 static int define_properties_valist(struct connman_element *element,
859                                                                 va_list args)
860 {
861         enum connman_property_id id;
862
863         DBG("element %p name %s", element, element->name);
864
865         id = va_arg(args, enum connman_property_id);
866
867         while (id != CONNMAN_PROPERTY_ID_INVALID) {
868
869                 DBG("property %d", id);
870
871                 create_property(element, id);
872
873                 id = va_arg(args, enum connman_property_id);
874         }
875
876         return 0;
877 }
878
879 /**
880  * connman_element_define_properties:
881  * @element: an element
882  * @varargs: list of property identifiers
883  *
884  * Define the valid properties for an element.
885  *
886  * Returns: %0 on success
887  */
888 int connman_element_define_properties(struct connman_element *element, ...)
889 {
890         va_list args;
891         int err;
892
893         DBG("element %p name %s", element, element->name);
894
895         va_start(args, element);
896
897         err = define_properties_valist(element, args);
898
899         va_end(args);
900
901         return err;
902 }
903
904 int connman_element_create_property(struct connman_element *element,
905                                                 const char *name, int type)
906 {
907         return -EIO;
908 }
909
910 int connman_element_set_property(struct connman_element *element,
911                                 enum connman_property_id id, const void *value)
912 {
913         switch (id) {
914         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
915                 connman_element_lock(element);
916                 g_free(element->ipv4.address);
917                 element->ipv4.address = g_strdup(*((const char **) value));
918                 connman_element_unlock(element);
919                 break;
920         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
921                 connman_element_lock(element);
922                 g_free(element->ipv4.netmask);
923                 element->ipv4.netmask = g_strdup(*((const char **) value));
924                 connman_element_unlock(element);
925                 break;
926         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
927                 connman_element_lock(element);
928                 g_free(element->ipv4.gateway);
929                 element->ipv4.gateway = g_strdup(*((const char **) value));
930                 connman_element_unlock(element);
931                 break;
932         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
933                 connman_element_lock(element);
934                 g_free(element->ipv4.nameserver);
935                 element->ipv4.nameserver = g_strdup(*((const char **) value));
936                 connman_element_unlock(element);
937                 break;
938         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
939                 connman_element_lock(element);
940                 g_free(element->wifi.security);
941                 element->wifi.security = g_strdup(*((const char **) value));
942                 connman_element_unlock(element);
943                 break;
944         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
945                 connman_element_lock(element);
946                 g_free(element->wifi.passphrase);
947                 element->wifi.passphrase = g_strdup(*((const char **) value));
948                 connman_element_unlock(element);
949                 break;
950         default:
951                 return -EINVAL;
952         }
953
954         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
955                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
956                                 DBUS_TYPE_OBJECT_PATH, &element->path,
957                                                         DBUS_TYPE_INVALID);
958
959         return 0;
960 }
961
962 int connman_element_get_value(struct connman_element *element,
963                                 enum connman_property_id id, void *value)
964 {
965         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
966                 return -EINVAL;
967
968         switch (id) {
969         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
970                 if (element->ipv4.address == NULL)
971                         return connman_element_get_value(element->parent,
972                                                                 id, value);
973                 connman_element_lock(element);
974                 *((char **) value) = element->ipv4.address;
975                 connman_element_unlock(element);
976                 break;
977         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
978                 if (element->ipv4.netmask == NULL)
979                         return connman_element_get_value(element->parent,
980                                                                 id, value);
981                 connman_element_lock(element);
982                 *((char **) value) = element->ipv4.netmask;
983                 connman_element_unlock(element);
984                 break;
985         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
986                 if (element->ipv4.gateway == NULL)
987                         return connman_element_get_value(element->parent,
988                                                                 id, value);
989                 connman_element_lock(element);
990                 *((char **) value) = element->ipv4.gateway;
991                 connman_element_unlock(element);
992                 break;
993         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
994                 if (element->ipv4.nameserver == NULL)
995                         return connman_element_get_value(element->parent,
996                                                                 id, value);
997                 connman_element_lock(element);
998                 *((char **) value) = element->ipv4.nameserver;
999                 connman_element_unlock(element);
1000                 break;
1001         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1002                 if (element->wifi.security == NULL)
1003                         return connman_element_get_value(element->parent,
1004                                                                 id, value);
1005                 connman_element_lock(element);
1006                 *((char **) value) = element->wifi.security;
1007                 connman_element_unlock(element);
1008                 break;
1009         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1010                 if (element->wifi.passphrase == NULL)
1011                         return connman_element_get_value(element->parent,
1012                                                                 id, value);
1013                 connman_element_lock(element);
1014                 *((char **) value) = element->wifi.passphrase;
1015                 connman_element_unlock(element);
1016                 break;
1017         default:
1018                 return -EINVAL;
1019         }
1020
1021         return 0;
1022 }
1023
1024 gboolean connman_element_get_static_property(struct connman_element *element,
1025                                                 const char *name, void *value)
1026 {
1027         GSList *list;
1028         gboolean found = FALSE;
1029
1030         DBG("element %p name %s", element, element->name);
1031
1032         connman_element_lock(element);
1033
1034         for (list = element->properties; list; list = list->next) {
1035                 struct connman_property *property = list->data;
1036
1037                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1038                         continue;
1039
1040                 if (g_str_equal(property->name, name) == TRUE) {
1041                         *((char **) value) = property->value;
1042                         found = TRUE;
1043                         break;
1044                 }
1045         }
1046
1047         connman_element_unlock(element);
1048
1049         return found;
1050 }
1051
1052 gboolean connman_element_get_static_array_property(struct connman_element *element,
1053                                         const char *name, void *value, int *len)
1054 {
1055         GSList *list;
1056         gboolean found = FALSE;
1057
1058         DBG("element %p name %s", element, element->name);
1059
1060         connman_element_lock(element);
1061
1062         for (list = element->properties; list; list = list->next) {
1063                 struct connman_property *property = list->data;
1064
1065                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1066                         continue;
1067
1068                 if (g_str_equal(property->name, name) == TRUE) {
1069                         *((char **) value) = property->value;
1070                         *len = property->size;
1071                         found = TRUE;
1072                         break;
1073                 }
1074         }
1075
1076         connman_element_unlock(element);
1077
1078         return found;
1079 }
1080
1081 gboolean connman_element_match_static_property(struct connman_element *element,
1082                                         const char *name, const void *value)
1083 {
1084         GSList *list;
1085         gboolean result = FALSE;
1086
1087         DBG("element %p name %s", element, element->name);
1088
1089         connman_element_lock(element);
1090
1091         for (list = element->properties; list; list = list->next) {
1092                 struct connman_property *property = list->data;
1093
1094                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1095                         continue;
1096
1097                 if (g_str_equal(property->name, name) == FALSE)
1098                         continue;
1099
1100                 if (property->type == DBUS_TYPE_STRING)
1101                         result = g_str_equal(property->value,
1102                                                 *((const char **) value));
1103
1104                 if (result == TRUE)
1105                         break;
1106         }
1107
1108         connman_element_unlock(element);
1109
1110         return result;
1111 }
1112
1113 /**
1114  * connman_element_register:
1115  * @element: the element to register
1116  * @parent: the parent to register the element with
1117  *
1118  * Register an element with the core. It will be register under the given
1119  * parent of if %NULL is provided under the root element.
1120  *
1121  * Returns: %0 on success
1122  */
1123 int connman_element_register(struct connman_element *element,
1124                                         struct connman_element *parent)
1125 {
1126         DBG("element %p name %s parent %p", element, element->name, parent);
1127
1128         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1129                 if (g_pattern_match_simple(device_filter,
1130                                                 element->name) == FALSE) {
1131                         DBG("ignoring %s device", element->name);
1132                         return -EPERM;
1133                 }
1134         }
1135
1136         if (connman_element_ref(element) == NULL)
1137                 return -EINVAL;
1138
1139         connman_element_lock(element);
1140
1141         if (element->name == NULL) {
1142                 element->name = g_strdup(type2string(element->type));
1143                 if (element->name == NULL) {
1144                         connman_element_unlock(element);
1145                         return -EINVAL;
1146                 }
1147         }
1148
1149         element->parent = parent;
1150
1151         connman_element_unlock(element);
1152
1153         if (thread_register != NULL)
1154                 g_thread_pool_push(thread_register, element, NULL);
1155
1156         return 0;
1157 }
1158
1159 void connman_element_unregister(struct connman_element *element)
1160 {
1161         DBG("element %p name %s", element, element->name);
1162
1163         if (thread_unregister != NULL)
1164                 g_thread_pool_push(thread_unregister, element, NULL);
1165 }
1166
1167 void connman_element_unregister_children(struct connman_element *element)
1168 {
1169         DBG("element %p name %s", element, element->name);
1170
1171         if (thread_unregister_children != NULL)
1172                 g_thread_pool_push(thread_unregister_children, element, NULL);
1173 }
1174
1175 static gboolean update_element(GNode *node, gpointer user_data)
1176 {
1177         struct connman_element *element = node->data;
1178
1179         DBG("element %p name %s", element, element->name);
1180
1181         if (element->driver && element->driver->update)
1182                 element->driver->update(element);
1183
1184         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1185                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1186                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1187                                                         DBUS_TYPE_INVALID);
1188
1189         return FALSE;
1190 }
1191
1192 void connman_element_update(struct connman_element *element)
1193 {
1194         GNode *node;
1195
1196         DBG("element %p name %s", element, element->name);
1197
1198         g_static_rw_lock_reader_lock(&element_lock);
1199
1200         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1201
1202         if (node != NULL)
1203                 g_node_traverse(node, G_PRE_ORDER,
1204                                 G_TRAVERSE_ALL, -1, update_element, NULL);
1205
1206         g_static_rw_lock_reader_unlock(&element_lock);
1207 }
1208
1209 int connman_element_set_enabled(struct connman_element *element,
1210                                                         gboolean enabled)
1211 {
1212         if (element->enabled == enabled)
1213                 return 0;
1214
1215         element->enabled = enabled;
1216
1217         connman_element_update(element);
1218
1219         return 0;
1220 }
1221
1222 static void register_element(gpointer data, gpointer user_data)
1223 {
1224         struct connman_element *element = data;
1225         const gchar *basepath;
1226         GSList *list;
1227         GNode *node;
1228
1229         g_static_rw_lock_writer_lock(&element_lock);
1230
1231         connman_element_lock(element);
1232
1233         if (element->parent) {
1234                 node = g_node_find(element_root, G_PRE_ORDER,
1235                                         G_TRAVERSE_ALL, element->parent);
1236                 basepath = element->parent->path;
1237
1238                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1239                         element->subtype = element->parent->subtype;
1240         } else {
1241                 element->parent = element_root->data;
1242
1243                 node = element_root;
1244                 basepath = "";
1245         }
1246
1247         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1248
1249         set_reference_properties(element);
1250
1251         connman_element_unlock(element);
1252
1253         DBG("element %p path %s", element, element->path);
1254
1255         __connman_element_load(element);
1256
1257         g_node_append_data(node, element);
1258
1259         if (g_dbus_register_interface(connection, element->path,
1260                                         CONNMAN_ELEMENT_INTERFACE,
1261                                         element_methods, element_signals,
1262                                         NULL, element, NULL) == FALSE)
1263                 connman_error("Failed to register %s", element->path);
1264
1265         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1266                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
1267                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1268                                                         DBUS_TYPE_INVALID);
1269
1270         g_static_rw_lock_writer_unlock(&element_lock);
1271
1272         __connman_element_store(element);
1273
1274         g_static_rw_lock_writer_lock(&element_lock);
1275
1276         for (list = driver_list; list; list = list->next) {
1277                 struct connman_driver *driver = list->data;
1278
1279                 if (match_driver(element, driver) == FALSE)
1280                         continue;
1281
1282                 DBG("driver %p name %s", driver, driver->name);
1283
1284                 if (driver->probe(element) == 0) {
1285                         connman_element_lock(element);
1286                         element->driver = driver;
1287                         connman_element_unlock(element);
1288                         break;
1289                 }
1290         }
1291
1292         g_static_rw_lock_writer_unlock(&element_lock);
1293 }
1294
1295 static gboolean remove_element(GNode *node, gpointer user_data)
1296 {
1297         struct connman_element *element = node->data;
1298         struct connman_element *root = user_data;
1299
1300         DBG("element %p name %s", element, element->name);
1301
1302         if (element == root)
1303                 return FALSE;
1304
1305         if (element->driver) {
1306                 if (element->driver->remove)
1307                         element->driver->remove(element);
1308
1309                 connman_element_lock(element);
1310                 element->driver = NULL;
1311                 connman_element_unlock(element);
1312         }
1313
1314         if (node != NULL) {
1315                 g_node_unlink(node);
1316                 g_node_destroy(node);
1317         }
1318
1319         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1320                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
1321                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1322                                                         DBUS_TYPE_INVALID);
1323
1324         g_dbus_unregister_interface(connection, element->path,
1325                                                 CONNMAN_ELEMENT_INTERFACE);
1326
1327         connman_element_unref(element);
1328
1329         return FALSE;
1330 }
1331
1332 static void unregister_element(gpointer data, gpointer user_data)
1333 {
1334         struct connman_element *element = data;
1335         GNode *node;
1336
1337         DBG("element %p name %s", element, element->name);
1338
1339         g_static_rw_lock_writer_lock(&element_lock);
1340
1341         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1342
1343         if (node != NULL)
1344                 g_node_traverse(node, G_POST_ORDER,
1345                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1346
1347         g_static_rw_lock_writer_unlock(&element_lock);
1348 }
1349
1350 static void unregister_children(gpointer data, gpointer user_data)
1351 {
1352         struct connman_element *element = data;
1353         GNode *node;
1354
1355         DBG("element %p name %s", element, element->name);
1356
1357         g_static_rw_lock_writer_lock(&element_lock);
1358
1359         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1360
1361         if (node != NULL)
1362                 g_node_traverse(node, G_POST_ORDER,
1363                                 G_TRAVERSE_ALL, -1, remove_element, element);
1364
1365         g_static_rw_lock_writer_unlock(&element_lock);
1366 }
1367
1368 int __connman_element_init(DBusConnection *conn, const char *device)
1369 {
1370         struct connman_element *element;
1371
1372         DBG("conn %p", conn);
1373
1374         connection = dbus_connection_ref(conn);
1375         if (connection == NULL)
1376                 return -EIO;
1377
1378         device_filter = g_strdup(device);
1379
1380         g_static_rw_lock_writer_lock(&element_lock);
1381
1382         element = connman_element_create("root");
1383
1384         element->path = g_strdup("/");
1385         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1386
1387         create_default_properties(element);
1388
1389         element_root = g_node_new(element);
1390
1391         g_static_rw_lock_writer_unlock(&element_lock);
1392
1393         thread_register = g_thread_pool_new(register_element,
1394                                                         NULL, 1, FALSE, NULL);
1395         thread_unregister = g_thread_pool_new(unregister_element,
1396                                                         NULL, 1, FALSE, NULL);
1397         thread_unregister_children = g_thread_pool_new(unregister_children,
1398                                                         NULL, 1, FALSE, NULL);
1399
1400         __connman_device_init();
1401
1402         return 0;
1403 }
1404
1405 static gboolean free_driver(GNode *node, gpointer data)
1406 {
1407         struct connman_element *element = node->data;
1408
1409         DBG("element %p name %s", element, element->name);
1410
1411         if (element->driver) {
1412                 if (element->driver->remove)
1413                         element->driver->remove(element);
1414
1415                 connman_element_lock(element);
1416                 element->driver = NULL;
1417                 connman_element_unlock(element);
1418         }
1419
1420         return FALSE;
1421 }
1422
1423 static gboolean free_node(GNode *node, gpointer data)
1424 {
1425         struct connman_element *element = node->data;
1426
1427         DBG("element %p name %s", element, element->name);
1428
1429         if (g_node_depth(node) > 1)
1430                 g_thread_pool_push(thread_unregister, element, NULL);
1431
1432         return FALSE;
1433 }
1434
1435 void __connman_element_cleanup(void)
1436 {
1437         DBG("");
1438
1439         __connman_device_cleanup();
1440
1441         g_thread_pool_free(thread_register, TRUE, TRUE);
1442         thread_register = NULL;
1443
1444         g_static_rw_lock_writer_lock(&element_lock);
1445         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1446                                                         free_driver, NULL);
1447         g_static_rw_lock_writer_unlock(&element_lock);
1448
1449         g_static_rw_lock_writer_lock(&element_lock);
1450         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1451                                                         free_node, NULL);
1452         g_static_rw_lock_writer_unlock(&element_lock);
1453
1454         g_thread_pool_free(thread_unregister, FALSE, TRUE);
1455         thread_unregister = NULL;
1456
1457         g_thread_pool_free(thread_unregister_children, FALSE, TRUE);
1458         thread_unregister_children = NULL;
1459
1460         g_static_rw_lock_writer_lock(&element_lock);
1461         g_node_destroy(element_root);
1462         element_root = NULL;
1463         g_static_rw_lock_writer_unlock(&element_lock);
1464
1465         g_free(device_filter);
1466
1467         dbus_connection_unref(connection);
1468 }