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