Load policy configuration from storage
[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 gchar *device_filter = NULL;
43
44 static struct {
45         enum connman_property_id id;
46         int type;
47         const char *name;
48         const void *value;
49 } propid_table[] = {
50         { CONNMAN_PROPERTY_ID_IPV4_METHOD,
51                 DBUS_TYPE_STRING, "IPv4.Method", "dhcp" },
52         { CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
53                 DBUS_TYPE_STRING, "IPv4.Address" },
54         { CONNMAN_PROPERTY_ID_IPV4_NETMASK,
55                 DBUS_TYPE_STRING, "IPv4.Netmask" },
56         { CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
57                 DBUS_TYPE_STRING, "IPv4.Gateway" },
58         { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
59                 DBUS_TYPE_STRING, "IPv4.Nameserver" },
60
61         { CONNMAN_PROPERTY_ID_WIFI_SECURITY,
62                 DBUS_TYPE_STRING, "WiFi.Security" },
63         { CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE,
64                 DBUS_TYPE_STRING, "WiFi.Passphrase" },
65
66         { }
67 };
68
69 static int propid2type(enum connman_property_id id)
70 {
71         int i;
72
73         for (i = 0; propid_table[i].name; i++) {
74                 if (propid_table[i].id == id)
75                         return propid_table[i].type;
76         }
77
78         return DBUS_TYPE_INVALID;
79 }
80
81 static const char *propid2name(enum connman_property_id id)
82 {
83         int i;
84
85         for (i = 0; propid_table[i].name; i++) {
86                 if (propid_table[i].id == id)
87                         return propid_table[i].name;
88         }
89
90         return NULL;
91 }
92
93 static const char *type2string(enum connman_element_type type)
94 {
95         switch (type) {
96         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
97                 return "unknown";
98         case CONNMAN_ELEMENT_TYPE_ROOT:
99                 return "root";
100         case CONNMAN_ELEMENT_TYPE_PROFILE:
101                 return "profile";
102         case CONNMAN_ELEMENT_TYPE_DEVICE:
103                 return "device";
104         case CONNMAN_ELEMENT_TYPE_NETWORK:
105                 return "network";
106         case CONNMAN_ELEMENT_TYPE_SERVICE:
107                 return "service";
108         case CONNMAN_ELEMENT_TYPE_IPV4:
109                 return "ipv4";
110         case CONNMAN_ELEMENT_TYPE_IPV6:
111                 return "ipv6";
112         case CONNMAN_ELEMENT_TYPE_DHCP:
113                 return "dhcp";
114         case CONNMAN_ELEMENT_TYPE_BOOTP:
115                 return "bootp";
116         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
117                 return "zeroconf";
118         case CONNMAN_ELEMENT_TYPE_RESOLVER:
119                 return "resolver";
120         case CONNMAN_ELEMENT_TYPE_CONNECTION:
121                 return "connection";
122         }
123
124         return NULL;
125 }
126
127 static const char *subtype2string(enum connman_element_subtype type)
128 {
129         switch (type) {
130         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
131                 return "unknown";
132         case CONNMAN_ELEMENT_SUBTYPE_FAKE:
133                 return "fake";
134         case CONNMAN_ELEMENT_SUBTYPE_NETWORK:
135                 return "network";
136         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
137                 return "ethernet";
138         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
139                 return "wifi";
140         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
141                 return "wimax";
142         case CONNMAN_ELEMENT_SUBTYPE_MODEM:
143                 return "modem";
144         case CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH:
145                 return "bluetooth";
146         }
147
148         return NULL;
149 }
150
151 const char *__connman_element_policy2string(enum connman_element_policy policy)
152 {
153         switch (policy) {
154         case CONNMAN_ELEMENT_POLICY_UNKNOWN:
155                 return "unknown";
156         case CONNMAN_ELEMENT_POLICY_OFF:
157                 return "off";
158         case CONNMAN_ELEMENT_POLICY_AUTO:
159                 return "auto";
160         case CONNMAN_ELEMENT_POLICY_IGNORE:
161                 return "ignore";
162         case CONNMAN_ELEMENT_POLICY_ASK:
163                 return "ask";
164         }
165
166         return NULL;
167 }
168
169 enum connman_element_policy __connman_element_string2policy(const char *policy)
170 {
171         if (strcasecmp(policy, "off") == 0)
172                 return CONNMAN_ELEMENT_POLICY_OFF;
173         else if (strcasecmp(policy, "ignore") == 0)
174                 return CONNMAN_ELEMENT_POLICY_IGNORE;
175         else if (strcasecmp(policy, "auto") == 0)
176                 return CONNMAN_ELEMENT_POLICY_AUTO;
177         else if (strcasecmp(policy, "ask") == 0)
178                 return CONNMAN_ELEMENT_POLICY_ASK;
179         else
180                 return CONNMAN_ELEMENT_POLICY_UNKNOWN;
181 }
182
183 static void append_property(DBusMessageIter *dict,
184                                 struct connman_property *property)
185 {
186         if (property->value == NULL)
187                 return;
188
189         if (property->type == DBUS_TYPE_ARRAY)
190                 connman_dbus_dict_append_array(dict, property->name,
191                         property->subtype, &property->value, property->size);
192         else
193                 connman_dbus_dict_append_variant(dict, property->name,
194                                         property->type, &property->value);
195 }
196
197 static void add_common_properties(struct connman_element *element,
198                                                 DBusMessageIter *dict)
199 {
200         const char *address = NULL, *netmask = NULL, *gateway = NULL;
201         GSList *list;
202
203         connman_element_get_value(element,
204                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
205         connman_element_get_value(element,
206                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
207         connman_element_get_value(element,
208                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
209
210         if (element->priority > 0)
211                 connman_dbus_dict_append_variant(dict, "Priority",
212                                         DBUS_TYPE_UINT16, &element->priority);
213
214         if (address != NULL)
215                 connman_dbus_dict_append_variant(dict, "IPv4.Address",
216                                                 DBUS_TYPE_STRING, &address);
217         if (netmask != NULL)
218                 connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
219                                                 DBUS_TYPE_STRING, &netmask);
220         if (gateway != NULL)
221                 connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
222                                                 DBUS_TYPE_STRING, &gateway);
223
224         if (element->wifi.security != NULL) {
225                 const char *passphrase = "";
226
227                 connman_dbus_dict_append_variant(dict, "WiFi.Security",
228                                 DBUS_TYPE_STRING, &element->wifi.security);
229
230                 if (element->wifi.passphrase != NULL)
231                         passphrase = element->wifi.passphrase;
232
233                 connman_dbus_dict_append_variant(dict, "WiFi.Passphrase",
234                                 DBUS_TYPE_STRING, &passphrase);
235         }
236
237         __connman_element_lock(element);
238
239         for (list = element->properties; list; list = list->next) {
240                 struct connman_property *property = list->data;
241
242                 append_property(dict, property);
243         }
244
245         __connman_element_unlock(element);
246 }
247
248 static void set_common_property(struct connman_element *element,
249                                 const char *name, DBusMessageIter *value)
250 {
251         GSList *list;
252
253         if (g_str_equal(name, "Priority") == TRUE) {
254                 dbus_message_iter_get_basic(value, &element->priority);
255                 return;
256         }
257
258         __connman_element_lock(element);
259
260         for (list = element->properties; list; list = list->next) {
261                 struct connman_property *property = list->data;
262                 const char *str;
263
264                 if (g_str_equal(property->name, name) == FALSE)
265                         continue;
266
267                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
268                         continue;
269
270                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
271
272                 if (property->type == DBUS_TYPE_STRING) {
273                         dbus_message_iter_get_basic(value, &str);
274                         g_free(property->value);
275                         property->value = g_strdup(str);
276                 } else
277                         property->value = NULL;
278         }
279
280         __connman_element_unlock(element);
281 }
282
283 static DBusMessage *do_update(DBusConnection *conn,
284                                         DBusMessage *msg, void *data)
285 {
286         struct connman_element *element = data;
287
288         DBG("conn %p", conn);
289
290         if (element->enabled == FALSE)
291                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
292
293         if (element->driver && element->driver->update) {
294                 DBG("Calling update callback");
295                 element->driver->update(element);
296         }
297
298         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
299 }
300
301 static DBusMessage *do_enable(DBusConnection *conn,
302                                         DBusMessage *msg, void *data)
303 {
304         struct connman_element *element = data;
305
306         DBG("conn %p", conn);
307
308         if (element->enabled == TRUE)
309                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
310
311         if (element->driver && element->driver->enable) {
312                 DBG("Calling enable callback");
313                 if (element->driver->enable(element) < 0)
314                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
315         }
316
317         element->enabled = TRUE;
318
319 #if 0
320         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
321                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
322                                 DBUS_TYPE_OBJECT_PATH, &element->path,
323                                                         DBUS_TYPE_INVALID);
324 #endif
325
326         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
327 }
328
329 static DBusMessage *do_disable(DBusConnection *conn,
330                                         DBusMessage *msg, void *data)
331 {
332         struct connman_element *element = data;
333
334         DBG("conn %p", conn);
335
336         if (element->enabled == FALSE)
337                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
338
339         if (element->driver && element->driver->disable) {
340                 DBG("Calling disable callback");
341                 if (element->driver->disable(element) < 0)
342                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
343         }
344
345         element->enabled = FALSE;
346
347 #if 0
348         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
349                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
350                                 DBUS_TYPE_OBJECT_PATH, &element->path,
351                                                         DBUS_TYPE_INVALID);
352 #endif
353
354         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
355 }
356
357 static void append_networks(DBusMessageIter *dict)
358 {
359         DBusMessageIter entry, value, iter;
360         const char *key = "Networks";
361
362         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
363                                                                 NULL, &entry);
364
365         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
366
367         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
368                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
369                                                                 &value);
370
371         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
372                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
373
374         __connman_element_list(CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
375
376         dbus_message_iter_close_container(&value, &iter);
377
378         dbus_message_iter_close_container(&entry, &value);
379
380         dbus_message_iter_close_container(dict, &entry);
381 }
382
383 static DBusMessage *get_device_properties(DBusConnection *conn,
384                                         DBusMessage *msg, void *data)
385 {
386         struct connman_element *element = data;
387         DBusMessage *reply;
388         DBusMessageIter array, dict;
389         const char *str;
390
391         DBG("conn %p", conn);
392
393         reply = dbus_message_new_method_return(msg);
394         if (reply == NULL)
395                 return NULL;
396
397         dbus_message_iter_init_append(reply, &array);
398
399         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
400                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
401                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
402                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
403
404         str = subtype2string(element->subtype);
405         if (str != NULL)
406                 connman_dbus_dict_append_variant(&dict, "Type",
407                                                 DBUS_TYPE_STRING, &str);
408
409         str = __connman_element_policy2string(element->policy);
410         if (str != NULL)
411                 connman_dbus_dict_append_variant(&dict, "Policy",
412                                                 DBUS_TYPE_STRING, &str);
413
414         connman_dbus_dict_append_variant(&dict, "Powered",
415                                         DBUS_TYPE_BOOLEAN, &element->enabled);
416
417         append_networks(&dict);
418
419         add_common_properties(element, &dict);
420
421         dbus_message_iter_close_container(&array, &dict);
422
423         return reply;
424 }
425
426 static DBusMessage *set_device_property(DBusConnection *conn,
427                                         DBusMessage *msg, void *data)
428 {
429         struct connman_element *element = data;
430         DBusMessageIter iter;
431         DBusMessageIter value;
432         const char *name;
433
434         DBG("conn %p", conn);
435
436         if (dbus_message_iter_init(msg, &iter) == FALSE)
437                 return __connman_error_invalid_arguments(msg);
438
439         dbus_message_iter_get_basic(&iter, &name);
440         dbus_message_iter_next(&iter);
441         dbus_message_iter_recurse(&iter, &value);
442
443         if (__connman_security_check_privileges(msg) < 0)
444                 return __connman_error_permission_denied(msg);
445
446         if (g_str_equal(name, "Powered") == TRUE) {
447                 dbus_bool_t powered;
448
449                 dbus_message_iter_get_basic(&value, &powered);
450
451                 if (powered == TRUE)
452                         do_enable(conn, msg, data);
453                 else
454                         do_disable(conn, msg, data);
455         } else
456                 set_common_property(element, name, &value);
457
458         __connman_element_store(element);
459
460         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
461 }
462
463 static DBusMessage *get_network_properties(DBusConnection *conn,
464                                         DBusMessage *msg, void *data)
465 {
466         struct connman_element *element = data;
467         DBusMessage *reply;
468         DBusMessageIter array, dict;
469         const char *str;
470
471         DBG("conn %p", conn);
472
473         reply = dbus_message_new_method_return(msg);
474         if (reply == NULL)
475                 return NULL;
476
477         dbus_message_iter_init_append(reply, &array);
478
479         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
480                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
481                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
482                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
483
484         str = __connman_element_policy2string(element->policy);
485         if (str != NULL)
486                 connman_dbus_dict_append_variant(&dict, "Policy",
487                                                 DBUS_TYPE_STRING, &str);
488
489         connman_dbus_dict_append_variant(&dict, "Connected",
490                                         DBUS_TYPE_BOOLEAN, &element->enabled);
491
492         add_common_properties(element, &dict);
493
494         dbus_message_iter_close_container(&array, &dict);
495
496         return reply;
497 }
498
499 static DBusMessage *set_network_property(DBusConnection *conn,
500                                         DBusMessage *msg, void *data)
501 {
502         struct connman_element *element = data;
503         DBusMessageIter iter;
504         DBusMessageIter value;
505         const char *name;
506
507         DBG("conn %p", conn);
508
509         if (dbus_message_iter_init(msg, &iter) == FALSE)
510                 return __connman_error_invalid_arguments(msg);
511
512         dbus_message_iter_get_basic(&iter, &name);
513         dbus_message_iter_next(&iter);
514         dbus_message_iter_recurse(&iter, &value);
515
516         if (__connman_security_check_privileges(msg) < 0)
517                 return __connman_error_permission_denied(msg);
518
519         if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
520                 const char *str;
521
522                 dbus_message_iter_get_basic(&value, &str);
523                 g_free(element->wifi.passphrase);
524                 element->wifi.passphrase = g_strdup(str);
525         } else
526                 set_common_property(element, name, &value);
527
528         __connman_element_store(element);
529
530         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
531 }
532
533 static DBusMessage *get_connection_properties(DBusConnection *conn,
534                                         DBusMessage *msg, void *data)
535 {
536         struct connman_element *element = data;
537         DBusMessage *reply;
538         DBusMessageIter array, dict;
539
540         DBG("conn %p", conn);
541
542         reply = dbus_message_new_method_return(msg);
543         if (reply == NULL)
544                 return NULL;
545
546         dbus_message_iter_init_append(reply, &array);
547
548         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
549                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
550                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
551                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
552
553         add_common_properties(element, &dict);
554
555         dbus_message_iter_close_container(&array, &dict);
556
557         return reply;
558 }
559
560 #if 0
561 static DBusMessage *get_properties(DBusConnection *conn,
562                                         DBusMessage *msg, void *data)
563 {
564         struct connman_element *element = data;
565         DBusMessage *reply;
566         DBusMessageIter array, dict;
567         const char *str;
568
569         DBG("conn %p", conn);
570
571         reply = dbus_message_new_method_return(msg);
572         if (reply == NULL)
573                 return NULL;
574
575         dbus_message_iter_init_append(reply, &array);
576
577         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
578                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
579                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
580                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
581
582         if (element->parent != NULL &&
583                         element->parent->type != CONNMAN_ELEMENT_TYPE_ROOT) {
584                 connman_dbus_dict_append_variant(&dict, "Parent",
585                                 DBUS_TYPE_OBJECT_PATH, &element->parent->path);
586         }
587
588         str = type2string(element->type);
589         if (str != NULL)
590                 connman_dbus_dict_append_variant(&dict, "Type",
591                                                 DBUS_TYPE_STRING, &str);
592         str = subtype2string(element->subtype);
593         if (str != NULL)
594                 connman_dbus_dict_append_variant(&dict, "Subtype",
595                                                 DBUS_TYPE_STRING, &str);
596
597         connman_dbus_dict_append_variant(&dict, "Enabled",
598                                         DBUS_TYPE_BOOLEAN, &element->enabled);
599
600         add_common_properties(element, &dict);
601
602         dbus_message_iter_close_container(&array, &dict);
603
604         return reply;
605 }
606
607 static DBusMessage *set_property(DBusConnection *conn,
608                                         DBusMessage *msg, void *data)
609 {
610         struct connman_element *element = data;
611         DBusMessageIter iter;
612         DBusMessageIter value;
613         const char *name;
614
615         DBG("conn %p", conn);
616
617         if (dbus_message_iter_init(msg, &iter) == FALSE)
618                 return __connman_error_invalid_arguments(msg);
619
620         dbus_message_iter_get_basic(&iter, &name);
621         dbus_message_iter_next(&iter);
622         dbus_message_iter_recurse(&iter, &value);
623
624         if (__connman_security_check_privileges(msg) < 0)
625                 return __connman_error_permission_denied(msg);
626
627         set_common_property(element, name, &value);
628
629         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
630 }
631
632 static DBusMessage *clear_property(DBusConnection *conn,
633                                         DBusMessage *msg, void *data)
634 {
635         struct connman_element *element = data;
636         const char *name;
637         GSList *list;
638
639         DBG("conn %p", conn);
640
641         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
642                                                 DBUS_TYPE_INVALID) == FALSE)
643                 return __connman_error_invalid_arguments(msg);
644
645         if (__connman_security_check_privileges(msg) < 0)
646                 return __connman_error_permission_denied(msg);
647
648         __connman_element_lock(element);
649
650         for (list = element->properties; list; list = list->next) {
651                 struct connman_property *property = list->data;
652
653                 if (g_str_equal(property->name, name) == FALSE)
654                         continue;
655
656                 if (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)
657                         continue;
658
659                 if (property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE)
660                         continue;
661
662                 property->flags |= CONNMAN_PROPERTY_FLAG_REFERENCE;
663
664                 if (property->type == DBUS_TYPE_STRING)
665                         g_free(property->value);
666
667                 property->value = NULL;
668         }
669
670         __connman_element_unlock(element);
671
672         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
673 }
674
675 static GDBusMethodTable element_methods[] = {
676         { "GetProperties", "",   "a{sv}", get_properties },
677         { "SetProperty",   "sv", "",      set_property   },
678         { "ClearProperty", "s",  "",      clear_property },
679         { "Update",        "",   "",      do_update      },
680         { "Enable",        "",   "",      do_enable      },
681         { "Disable",       "",   "",      do_disable     },
682         { },
683 };
684 #endif
685
686 static GDBusSignalTable element_signals[] = {
687         { "PropertyChanged", "sv" },
688         { },
689 };
690
691 static GDBusMethodTable device_methods[] = {
692         { "GetProperties", "",   "a{sv}", get_device_properties },
693         { "SetProperty",   "sv", "",      set_device_property   },
694         { "Scan",          "",   "",      do_update             },
695         { },
696 };
697
698 static GDBusMethodTable network_methods[] = {
699         { "GetProperties", "",   "a{sv}", get_network_properties },
700         { "SetProperty",   "sv", "",      set_network_property   },
701         { "Connect",       "",   "",      do_enable              },
702         { "Disconnect",    "",   "",      do_disable             },
703         { },
704 };
705
706 static GDBusMethodTable connection_methods[] = {
707         { "GetProperties", "",   "a{sv}", get_connection_properties },
708         { },
709 };
710
711 struct append_filter {
712         enum connman_element_type type;
713         DBusMessageIter *iter;
714 };
715
716 static gboolean append_path(GNode *node, gpointer user_data)
717 {
718         struct connman_element *element = node->data;
719         struct append_filter *filter = user_data;
720
721         DBG("element %p name %s", element, element->name);
722
723         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
724                 return FALSE;
725
726         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
727                                         filter->type != element->type)
728                 return FALSE;
729
730         dbus_message_iter_append_basic(filter->iter,
731                                 DBUS_TYPE_OBJECT_PATH, &element->path);
732
733         return FALSE;
734 }
735
736 void __connman_element_list(enum connman_element_type type,
737                                                 DBusMessageIter *iter)
738 {
739         struct append_filter filter = { type, iter };
740
741         DBG("");
742
743         g_static_rw_lock_reader_lock(&element_lock);
744         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
745                                                         append_path, &filter);
746         g_static_rw_lock_reader_unlock(&element_lock);
747 }
748
749 struct count_data {
750         enum connman_element_type type;
751         int count;
752 };
753
754 static gboolean count_element(GNode *node, gpointer user_data)
755 {
756         struct connman_element *element = node->data;
757         struct count_data *data = user_data;
758
759         DBG("element %p name %s", element, element->name);
760
761         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
762                 return FALSE;
763
764         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
765                                         data->type != element->type)
766                 return FALSE;
767
768         data->count++;
769
770         return FALSE;
771 }
772
773 int __connman_element_count(enum connman_element_type type)
774 {
775         struct count_data data = { type, 0 };
776
777         DBG("");
778
779         g_static_rw_lock_reader_lock(&element_lock);
780         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
781                                                         count_element, &data);
782         g_static_rw_lock_reader_unlock(&element_lock);
783
784         return data.count;
785 }
786
787 static gint compare_priority(gconstpointer a, gconstpointer b)
788 {
789         const struct connman_driver *driver1 = a;
790         const struct connman_driver *driver2 = b;
791
792         return driver2->priority - driver1->priority;
793 }
794
795 static gboolean match_driver(struct connman_element *element,
796                                         struct connman_driver *driver)
797 {
798         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
799                 return FALSE;
800
801         if (element->type != driver->type &&
802                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
803                 return FALSE;
804
805         if (element->subtype == driver->subtype ||
806                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
807                 return TRUE;
808
809         return FALSE;
810 }
811
812 static void enable_element(struct connman_element *element)
813 {
814         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
815                 return;
816
817         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
818                 return;
819
820         if (element->driver && element->driver->enable) {
821                 if (element->driver->enable(element) == 0)
822                         element->enabled = TRUE;
823         }
824 }
825
826 static gboolean probe_driver(GNode *node, gpointer data)
827 {
828         struct connman_element *element = node->data;
829         struct connman_driver *driver = data;
830
831         DBG("element %p name %s", element, element->name);
832
833         if (!element->driver && match_driver(element, driver) == TRUE) {
834                 if (driver->probe(element) < 0)
835                         return FALSE;
836
837                 __connman_element_lock(element);
838                 element->driver = driver;
839                 __connman_element_unlock(element);
840
841                 enable_element(element);
842         }
843
844         return FALSE;
845 }
846
847 void __connman_driver_rescan(struct connman_driver *driver)
848 {
849         DBG("driver %p name %s", driver, driver->name);
850
851         if (!driver->probe)
852                 return;
853
854         g_static_rw_lock_writer_lock(&element_lock);
855
856         if (element_root != NULL)
857                 g_node_traverse(element_root, G_PRE_ORDER,
858                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
859
860         g_static_rw_lock_writer_unlock(&element_lock);
861 }
862
863 /**
864  * connman_driver_register:
865  * @driver: driver definition
866  *
867  * Register a new driver
868  *
869  * Returns: %0 on success
870  */
871 int connman_driver_register(struct connman_driver *driver)
872 {
873         DBG("driver %p name %s", driver, driver->name);
874
875         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
876                 return -EINVAL;
877
878         if (!driver->probe)
879                 return -EINVAL;
880
881         g_static_rw_lock_writer_lock(&element_lock);
882
883         driver_list = g_slist_insert_sorted(driver_list, driver,
884                                                         compare_priority);
885
886         if (element_root != NULL)
887                 g_node_traverse(element_root, G_PRE_ORDER,
888                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
889
890         g_static_rw_lock_writer_unlock(&element_lock);
891
892         return 0;
893 }
894
895 static void disable_element(struct connman_element *element)
896 {
897         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
898                 return;
899
900         if (element->enabled == FALSE)
901                 return;
902
903         if (element->driver && element->driver->disable) {
904                 if (element->driver->disable(element) == 0)
905                         element->enabled = FALSE;
906         }
907 }
908
909 static gboolean remove_driver(GNode *node, gpointer data)
910 {
911         struct connman_element *element = node->data;
912         struct connman_driver *driver = data;
913
914         DBG("element %p name %s", element, element->name);
915
916         if (element->driver == driver) {
917                 disable_element(element);
918
919                 if (driver->remove)
920                         driver->remove(element);
921
922                 __connman_element_lock(element);
923                 element->driver = NULL;
924                 __connman_element_unlock(element);
925         }
926
927         return FALSE;
928 }
929
930 /**
931  * connman_driver_unregister:
932  * @driver: driver definition
933  *
934  * Remove a previously registered driver
935  */
936 void connman_driver_unregister(struct connman_driver *driver)
937 {
938         DBG("driver %p name %s", driver, driver->name);
939
940         g_static_rw_lock_writer_lock(&element_lock);
941
942         driver_list = g_slist_remove(driver_list, driver);
943
944         if (element_root != NULL)
945                 g_node_traverse(element_root, G_POST_ORDER,
946                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
947
948         g_static_rw_lock_writer_unlock(&element_lock);
949 }
950
951 /**
952  * connman_element_create:
953  * @name: element name
954  *
955  * Allocate a new element and assign the given #name to it. If the name
956  * is #NULL, it will be later on created based on the element type.
957  *
958  * Returns: a newly-allocated #connman_element structure
959  */
960 struct connman_element *connman_element_create(const char *name)
961 {
962         struct connman_element *element;
963
964         element = g_try_new0(struct connman_element, 1);
965         if (element == NULL)
966                 return NULL;
967
968         DBG("element %p", element);
969
970         element->refcount = 1;
971
972         element->name    = g_strdup(name);
973         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
974         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
975         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
976         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
977         element->index   = -1;
978         element->enabled = FALSE;
979
980         return element;
981 }
982
983 struct connman_element *connman_element_ref(struct connman_element *element)
984 {
985         DBG("element %p name %s refcount %d", element, element->name,
986                                 g_atomic_int_get(&element->refcount) + 1);
987
988         g_atomic_int_inc(&element->refcount);
989
990         return element;
991 }
992
993 static void free_properties(struct connman_element *element)
994 {
995         GSList *list;
996
997         DBG("element %p name %s", element, element->name);
998
999         __connman_element_lock(element);
1000
1001         for (list = element->properties; list; list = list->next) {
1002                 struct connman_property *property = list->data;
1003
1004                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1005                         g_free(property->value);
1006
1007                 g_free(property->name);
1008                 g_free(property);
1009         }
1010
1011         g_slist_free(element->properties);
1012
1013         element->properties = NULL;
1014
1015         __connman_element_unlock(element);
1016 }
1017
1018 void connman_element_unref(struct connman_element *element)
1019 {
1020         DBG("element %p name %s refcount %d", element, element->name,
1021                                 g_atomic_int_get(&element->refcount) - 1);
1022
1023         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
1024                 free_properties(element);
1025                 g_free(element->ipv4.address);
1026                 g_free(element->ipv4.netmask);
1027                 g_free(element->ipv4.gateway);
1028                 g_free(element->ipv4.network);
1029                 g_free(element->ipv4.broadcast);
1030                 g_free(element->ipv4.nameserver);
1031                 g_free(element->path);
1032                 g_free(element->name);
1033                 g_free(element);
1034         }
1035 }
1036
1037 int connman_element_add_static_property(struct connman_element *element,
1038                                 const char *name, int type, const void *value)
1039 {
1040         struct connman_property *property;
1041
1042         DBG("element %p name %s", element, element->name);
1043
1044         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE &&
1045                                                 type != DBUS_TYPE_INT32)
1046                 return -EINVAL;
1047
1048         property = g_try_new0(struct connman_property, 1);
1049         if (property == NULL)
1050                 return -ENOMEM;
1051
1052         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
1053         property->id    = CONNMAN_PROPERTY_ID_INVALID;
1054         property->name  = g_strdup(name);
1055         property->type  = type;
1056
1057         DBG("name %s type %d value %p", name, type, value);
1058
1059         switch (type) {
1060         case DBUS_TYPE_STRING:
1061                 property->value = g_strdup(*((const char **) value));
1062                 break;
1063         case DBUS_TYPE_BYTE:
1064                 property->value = g_try_malloc(1);
1065                 if (property->value != NULL)
1066                         memcpy(property->value, value, 1);
1067                 break;
1068         case DBUS_TYPE_INT32:
1069                 property->value = g_try_malloc(sizeof(gint32));
1070                 if (property->value != NULL)
1071                         memcpy(property->value, value, sizeof(gint32));
1072                 break;
1073         }
1074
1075         __connman_element_lock(element);
1076         element->properties = g_slist_append(element->properties, property);
1077         __connman_element_unlock(element);
1078
1079         return 0;
1080 }
1081
1082 int connman_element_add_static_array_property(struct connman_element *element,
1083                         const char *name, int type, const void *value, int len)
1084 {
1085         struct connman_property *property;
1086
1087         DBG("element %p name %s", element, element->name);
1088
1089         if (type != DBUS_TYPE_BYTE)
1090                 return -EINVAL;
1091
1092         property = g_try_new0(struct connman_property, 1);
1093         if (property == NULL)
1094                 return -ENOMEM;
1095
1096         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1097         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1098         property->name    = g_strdup(name);
1099         property->type    = DBUS_TYPE_ARRAY;
1100         property->subtype = type;
1101
1102         DBG("name %s type %d value %p", name, type, value);
1103
1104         switch (type) {
1105         case DBUS_TYPE_BYTE:
1106                 property->value = g_try_malloc(len);
1107                 if (property->value != NULL) {
1108                         memcpy(property->value,
1109                                 *((const unsigned char **) value), len);
1110                         property->size = len;
1111                 }
1112                 break;
1113         }
1114
1115         __connman_element_lock(element);
1116         element->properties = g_slist_append(element->properties, property);
1117         __connman_element_unlock(element);
1118
1119         return 0;
1120 }
1121
1122 static void *get_reference_value(struct connman_element *element,
1123                                                 enum connman_property_id id)
1124 {
1125         GSList *list;
1126
1127         DBG("element %p name %s", element, element->name);
1128
1129         for (list = element->properties; list; list = list->next) {
1130                 struct connman_property *property = list->data;
1131
1132                 if (property->id != id)
1133                         continue;
1134
1135                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1136                         return property->value;
1137         }
1138
1139         if (element->parent == NULL)
1140                 return NULL;
1141
1142         return get_reference_value(element->parent, id);
1143 }
1144
1145 static void set_reference_properties(struct connman_element *element)
1146 {
1147         GSList *list;
1148
1149         DBG("element %p name %s", element, element->name);
1150
1151         for (list = element->properties; list; list = list->next) {
1152                 struct connman_property *property = list->data;
1153
1154                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1155                         continue;
1156
1157                 property->value = get_reference_value(element->parent,
1158                                                                 property->id);
1159         }
1160 }
1161
1162 static struct connman_property *create_property(struct connman_element *element,
1163                                                 enum connman_property_id id)
1164 {
1165         struct connman_property *property;
1166         GSList *list;
1167
1168         DBG("element %p name %s", element, element->name);
1169
1170         __connman_element_lock(element);
1171
1172         for (list = element->properties; list; list = list->next) {
1173                 property = list->data;
1174
1175                 if (property->id == id)
1176                         goto unlock;
1177         }
1178
1179         property = g_try_new0(struct connman_property, 1);
1180         if (property == NULL)
1181                 goto unlock;
1182
1183         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1184         property->id    = id;
1185         property->name  = g_strdup(propid2name(id));
1186         property->type  = propid2type(id);
1187
1188         if (property->name == NULL) {
1189                 g_free(property);
1190                 property = NULL;
1191                 goto unlock;
1192         }
1193
1194         element->properties = g_slist_append(element->properties, property);
1195
1196 unlock:
1197         __connman_element_unlock(element);
1198
1199         return property;
1200 }
1201
1202 static void create_default_properties(struct connman_element *element)
1203 {
1204         struct connman_property *property;
1205         int i;
1206
1207         DBG("element %p name %s", element, element->name);
1208
1209         for (i = 0; propid_table[i].name; i++) {
1210                 DBG("property %s", propid_table[i].name);
1211
1212                 property = create_property(element, propid_table[i].id);
1213
1214                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1215
1216                 if (propid_table[i].type != DBUS_TYPE_STRING)
1217                         continue;
1218
1219                 if (propid_table[i].value)
1220                         property->value = g_strdup(propid_table[i].value);
1221                 else
1222                         property->value = g_strdup("");
1223         }
1224 }
1225
1226 static int define_properties_valist(struct connman_element *element,
1227                                                                 va_list args)
1228 {
1229         enum connman_property_id id;
1230
1231         DBG("element %p name %s", element, element->name);
1232
1233         id = va_arg(args, enum connman_property_id);
1234
1235         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1236
1237                 DBG("property %d", id);
1238
1239                 create_property(element, id);
1240
1241                 id = va_arg(args, enum connman_property_id);
1242         }
1243
1244         return 0;
1245 }
1246
1247 /**
1248  * connman_element_define_properties:
1249  * @element: an element
1250  * @varargs: list of property identifiers
1251  *
1252  * Define the valid properties for an element.
1253  *
1254  * Returns: %0 on success
1255  */
1256 int connman_element_define_properties(struct connman_element *element, ...)
1257 {
1258         va_list args;
1259         int err;
1260
1261         DBG("element %p name %s", element, element->name);
1262
1263         va_start(args, element);
1264
1265         err = define_properties_valist(element, args);
1266
1267         va_end(args);
1268
1269         return err;
1270 }
1271
1272 int connman_element_create_property(struct connman_element *element,
1273                                                 const char *name, int type)
1274 {
1275         return -EIO;
1276 }
1277
1278 int connman_element_set_property(struct connman_element *element,
1279                                 enum connman_property_id id, const void *value)
1280 {
1281         switch (id) {
1282         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1283                 __connman_element_lock(element);
1284                 g_free(element->ipv4.address);
1285                 element->ipv4.address = g_strdup(*((const char **) value));
1286                 __connman_element_unlock(element);
1287                 break;
1288         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1289                 __connman_element_lock(element);
1290                 g_free(element->ipv4.netmask);
1291                 element->ipv4.netmask = g_strdup(*((const char **) value));
1292                 __connman_element_unlock(element);
1293                 break;
1294         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1295                 __connman_element_lock(element);
1296                 g_free(element->ipv4.gateway);
1297                 element->ipv4.gateway = g_strdup(*((const char **) value));
1298                 __connman_element_unlock(element);
1299                 break;
1300         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1301                 __connman_element_lock(element);
1302                 g_free(element->ipv4.nameserver);
1303                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1304                 __connman_element_unlock(element);
1305                 break;
1306         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1307                 __connman_element_lock(element);
1308                 g_free(element->wifi.security);
1309                 element->wifi.security = g_strdup(*((const char **) value));
1310                 __connman_element_unlock(element);
1311                 break;
1312         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1313                 __connman_element_lock(element);
1314                 g_free(element->wifi.passphrase);
1315                 element->wifi.passphrase = g_strdup(*((const char **) value));
1316                 __connman_element_unlock(element);
1317                 break;
1318         default:
1319                 return -EINVAL;
1320         }
1321
1322 #if 0
1323         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1324                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1325                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1326                                                         DBUS_TYPE_INVALID);
1327 #endif
1328
1329         return 0;
1330 }
1331
1332 int connman_element_get_value(struct connman_element *element,
1333                                 enum connman_property_id id, void *value)
1334 {
1335         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1336                 return -EINVAL;
1337
1338         switch (id) {
1339         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1340                 if (element->ipv4.address == NULL)
1341                         return connman_element_get_value(element->parent,
1342                                                                 id, value);
1343                 __connman_element_lock(element);
1344                 *((char **) value) = element->ipv4.address;
1345                 __connman_element_unlock(element);
1346                 break;
1347         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1348                 if (element->ipv4.netmask == NULL)
1349                         return connman_element_get_value(element->parent,
1350                                                                 id, value);
1351                 __connman_element_lock(element);
1352                 *((char **) value) = element->ipv4.netmask;
1353                 __connman_element_unlock(element);
1354                 break;
1355         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1356                 if (element->ipv4.gateway == NULL)
1357                         return connman_element_get_value(element->parent,
1358                                                                 id, value);
1359                 __connman_element_lock(element);
1360                 *((char **) value) = element->ipv4.gateway;
1361                 __connman_element_unlock(element);
1362                 break;
1363         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1364                 if (element->ipv4.nameserver == NULL)
1365                         return connman_element_get_value(element->parent,
1366                                                                 id, value);
1367                 __connman_element_lock(element);
1368                 *((char **) value) = element->ipv4.nameserver;
1369                 __connman_element_unlock(element);
1370                 break;
1371         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1372                 if (element->wifi.security == NULL)
1373                         return connman_element_get_value(element->parent,
1374                                                                 id, value);
1375                 __connman_element_lock(element);
1376                 *((char **) value) = element->wifi.security;
1377                 __connman_element_unlock(element);
1378                 break;
1379         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1380                 if (element->wifi.passphrase == NULL)
1381                         return connman_element_get_value(element->parent,
1382                                                                 id, value);
1383                 __connman_element_lock(element);
1384                 *((char **) value) = element->wifi.passphrase;
1385                 __connman_element_unlock(element);
1386                 break;
1387         default:
1388                 return -EINVAL;
1389         }
1390
1391         return 0;
1392 }
1393
1394 gboolean connman_element_get_static_property(struct connman_element *element,
1395                                                 const char *name, void *value)
1396 {
1397         GSList *list;
1398         gboolean found = FALSE;
1399
1400         DBG("element %p name %s", element, element->name);
1401
1402         __connman_element_lock(element);
1403
1404         for (list = element->properties; list; list = list->next) {
1405                 struct connman_property *property = list->data;
1406
1407                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1408                         continue;
1409
1410                 if (g_str_equal(property->name, name) == TRUE) {
1411                         switch (property->type) {
1412                         case DBUS_TYPE_STRING:
1413                                 *((char **) value) = property->value;
1414                                 break;
1415                         case DBUS_TYPE_BYTE:
1416                                 *((guint8 *) value) = *((guint8 *) property->value);
1417                                 break;
1418                         case DBUS_TYPE_INT32:
1419                                 *((gint32 *) value) = *((gint32 *) property->value);
1420                                 break;
1421                         }
1422                         found = TRUE;
1423                         break;
1424                 }
1425         }
1426
1427         __connman_element_unlock(element);
1428
1429         return found;
1430 }
1431
1432 gboolean connman_element_get_static_array_property(struct connman_element *element,
1433                                         const char *name, void *value, int *len)
1434 {
1435         GSList *list;
1436         gboolean found = FALSE;
1437
1438         DBG("element %p name %s", element, element->name);
1439
1440         __connman_element_lock(element);
1441
1442         for (list = element->properties; list; list = list->next) {
1443                 struct connman_property *property = list->data;
1444
1445                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1446                         continue;
1447
1448                 if (g_str_equal(property->name, name) == TRUE) {
1449                         *((char **) value) = property->value;
1450                         *len = property->size;
1451                         found = TRUE;
1452                         break;
1453                 }
1454         }
1455
1456         __connman_element_unlock(element);
1457
1458         return found;
1459 }
1460
1461 gboolean connman_element_match_static_property(struct connman_element *element,
1462                                         const char *name, const void *value)
1463 {
1464         GSList *list;
1465         gboolean result = FALSE;
1466
1467         DBG("element %p name %s", element, element->name);
1468
1469         __connman_element_lock(element);
1470
1471         for (list = element->properties; list; list = list->next) {
1472                 struct connman_property *property = list->data;
1473
1474                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1475                         continue;
1476
1477                 if (g_str_equal(property->name, name) == FALSE)
1478                         continue;
1479
1480                 if (property->type == DBUS_TYPE_STRING)
1481                         result = g_str_equal(property->value,
1482                                                 *((const char **) value));
1483
1484                 if (result == TRUE)
1485                         break;
1486         }
1487
1488         __connman_element_unlock(element);
1489
1490         return result;
1491 }
1492
1493 static void append_devices(DBusMessageIter *entry)
1494 {
1495         DBusMessageIter value, iter;
1496         const char *key = "Devices";
1497
1498         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1499
1500         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1501                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1502                                                                 &value);
1503
1504         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1505                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1506
1507         __connman_element_list(CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1508
1509         dbus_message_iter_close_container(&value, &iter);
1510
1511         dbus_message_iter_close_container(entry, &value);
1512 }
1513
1514 static void emit_devices_signal(DBusConnection *conn)
1515 {
1516         DBusMessage *signal;
1517         DBusMessageIter entry;
1518
1519         DBG("conn %p", conn);
1520
1521         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1522                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1523         if (signal == NULL)
1524                 return;
1525
1526         dbus_message_iter_init_append(signal, &entry);
1527
1528         append_devices(&entry);
1529
1530         g_dbus_send_message(conn, signal);
1531 }
1532
1533 static void append_connections(DBusMessageIter *entry)
1534 {
1535         DBusMessageIter value, iter;
1536         const char *key = "Connections";
1537
1538         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1539
1540         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1541                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1542                                                                 &value);
1543
1544         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1545                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1546
1547         __connman_element_list(CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1548
1549         dbus_message_iter_close_container(&value, &iter);
1550
1551         dbus_message_iter_close_container(entry, &value);
1552 }
1553
1554 static void emit_connections_signal(DBusConnection *conn)
1555 {
1556         DBusMessage *signal;
1557         DBusMessageIter entry;
1558
1559         DBG("conn %p", conn);
1560
1561         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1562                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1563         if (signal == NULL)
1564                 return;
1565
1566         dbus_message_iter_init_append(signal, &entry);
1567
1568         append_connections(&entry);
1569
1570         g_dbus_send_message(conn, signal);
1571 }
1572
1573 static void append_state(DBusMessageIter *entry, const char *state)
1574 {
1575         DBusMessageIter value;
1576         const char *key = "State";
1577
1578         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1579
1580         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1581                                         DBUS_TYPE_STRING_AS_STRING, &value);
1582
1583         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1584
1585         dbus_message_iter_close_container(entry, &value);
1586 }
1587
1588 static void emit_state_change(DBusConnection *conn, const char *state)
1589 {
1590         DBusMessage *signal;
1591         DBusMessageIter entry;
1592
1593         DBG("conn %p", conn);
1594
1595         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1596                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1597         if (signal == NULL)
1598                 return;
1599
1600         dbus_message_iter_init_append(signal, &entry);
1601
1602         append_state(&entry, state);
1603
1604         g_dbus_send_message(conn, signal);
1605 }
1606
1607 static void register_element(gpointer data, gpointer user_data)
1608 {
1609         struct connman_element *element = data;
1610         const gchar *basepath;
1611         GSList *list;
1612         GNode *node;
1613
1614         g_static_rw_lock_writer_lock(&element_lock);
1615
1616         __connman_element_lock(element);
1617
1618         if (element->parent) {
1619                 node = g_node_find(element_root, G_PRE_ORDER,
1620                                         G_TRAVERSE_ALL, element->parent);
1621                 basepath = element->parent->path;
1622
1623                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1624                         element->subtype = element->parent->subtype;
1625         } else {
1626                 element->parent = element_root->data;
1627
1628                 node = element_root;
1629                 basepath = "";
1630         }
1631
1632         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1633
1634         set_reference_properties(element);
1635
1636         __connman_element_unlock(element);
1637
1638         DBG("element %p path %s", element, element->path);
1639
1640         __connman_element_load(element);
1641
1642         g_node_append_data(node, element);
1643
1644 #if 0
1645         if (g_dbus_register_interface(connection, element->path,
1646                                         CONNMAN_ELEMENT_INTERFACE,
1647                                         element_methods, element_signals,
1648                                         NULL, element, NULL) == FALSE)
1649                 connman_error("Failed to register %s element", element->path);
1650 #endif
1651
1652         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1653                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1654                 if (g_dbus_register_interface(connection, element->path,
1655                                         CONNMAN_DEVICE_INTERFACE,
1656                                         device_methods, element_signals,
1657                                         NULL, element, NULL) == FALSE)
1658                         connman_error("Failed to register %s device",
1659                                                                 element->path);
1660                 else
1661                         emit_devices_signal(connection);
1662         }
1663
1664         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1665                 if (g_dbus_register_interface(connection, element->path,
1666                                         CONNMAN_NETWORK_INTERFACE,
1667                                         network_methods, element_signals,
1668                                         NULL, element, NULL) == FALSE)
1669                         connman_error("Failed to register %s network",
1670                                                                 element->path);
1671         }
1672
1673         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1674                 if (g_dbus_register_interface(connection, element->path,
1675                                         CONNMAN_CONNECTION_INTERFACE,
1676                                         connection_methods, element_signals,
1677                                         NULL, element, NULL) == FALSE)
1678                         connman_error("Failed to register %s connection",
1679                                                                 element->path);
1680                 else {
1681                         emit_connections_signal(connection);
1682                         emit_state_change(connection, "online");
1683                 }
1684         }
1685
1686 #if 0
1687         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1688                                 CONNMAN_MANAGER_INTERFACE, "ElementAdded",
1689                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1690                                                         DBUS_TYPE_INVALID);
1691 #endif
1692
1693         g_static_rw_lock_writer_unlock(&element_lock);
1694
1695         __connman_element_store(element);
1696
1697         g_static_rw_lock_writer_lock(&element_lock);
1698
1699         for (list = driver_list; list; list = list->next) {
1700                 struct connman_driver *driver = list->data;
1701
1702                 if (match_driver(element, driver) == FALSE)
1703                         continue;
1704
1705                 DBG("driver %p name %s", driver, driver->name);
1706
1707                 if (driver->probe(element) == 0) {
1708                         __connman_element_lock(element);
1709                         element->driver = driver;
1710                         __connman_element_unlock(element);
1711
1712                         enable_element(element);
1713                         break;
1714                 }
1715         }
1716
1717         g_static_rw_lock_writer_unlock(&element_lock);
1718 }
1719
1720 /**
1721  * connman_element_register:
1722  * @element: the element to register
1723  * @parent: the parent to register the element with
1724  *
1725  * Register an element with the core. It will be register under the given
1726  * parent of if %NULL is provided under the root element.
1727  *
1728  * Returns: %0 on success
1729  */
1730 int connman_element_register(struct connman_element *element,
1731                                         struct connman_element *parent)
1732 {
1733         DBG("element %p name %s parent %p", element, element->name, parent);
1734
1735         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1736                 if (g_pattern_match_simple(device_filter,
1737                                                 element->name) == FALSE) {
1738                         DBG("ignoring %s device", element->name);
1739                         return -EPERM;
1740                 }
1741         }
1742
1743         if (connman_element_ref(element) == NULL)
1744                 return -EINVAL;
1745
1746         __connman_element_lock(element);
1747
1748         if (element->name == NULL) {
1749                 element->name = g_strdup(type2string(element->type));
1750                 if (element->name == NULL) {
1751                         __connman_element_unlock(element);
1752                         return -EINVAL;
1753                 }
1754         }
1755
1756         element->parent = parent;
1757
1758         __connman_element_unlock(element);
1759
1760         register_element(element, NULL);
1761
1762         return 0;
1763 }
1764
1765 static gboolean remove_element(GNode *node, gpointer user_data)
1766 {
1767         struct connman_element *element = node->data;
1768         struct connman_element *root = user_data;
1769
1770         DBG("element %p name %s", element, element->name);
1771
1772         if (element == root)
1773                 return FALSE;
1774
1775         if (element->driver) {
1776                 if (element->driver->remove)
1777                         element->driver->remove(element);
1778
1779                 __connman_element_lock(element);
1780                 element->driver = NULL;
1781                 __connman_element_unlock(element);
1782         }
1783
1784         if (node != NULL) {
1785                 g_node_unlink(node);
1786                 g_node_destroy(node);
1787         }
1788
1789 #if 0
1790         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1791                                 CONNMAN_MANAGER_INTERFACE, "ElementRemoved",
1792                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1793                                                         DBUS_TYPE_INVALID);
1794 #endif
1795
1796         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1797                 emit_state_change(connection, "offline");
1798                 emit_connections_signal(connection);
1799
1800                 g_dbus_unregister_interface(connection, element->path,
1801                                                 CONNMAN_CONNECTION_INTERFACE);
1802         }
1803
1804         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK)
1805                 g_dbus_unregister_interface(connection, element->path,
1806                                                 CONNMAN_NETWORK_INTERFACE);
1807
1808         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1809                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1810                 emit_devices_signal(connection);
1811
1812                 g_dbus_unregister_interface(connection, element->path,
1813                                                 CONNMAN_DEVICE_INTERFACE);
1814         }
1815
1816 #if 0
1817         g_dbus_unregister_interface(connection, element->path,
1818                                                 CONNMAN_ELEMENT_INTERFACE);
1819 #endif
1820
1821         connman_element_unref(element);
1822
1823         return FALSE;
1824 }
1825
1826 void connman_element_unregister(struct connman_element *element)
1827 {
1828         GNode *node;
1829
1830         DBG("element %p name %s", element, element->name);
1831
1832         g_static_rw_lock_writer_lock(&element_lock);
1833
1834         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1835
1836         if (node != NULL)
1837                 g_node_traverse(node, G_POST_ORDER,
1838                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1839
1840         g_static_rw_lock_writer_unlock(&element_lock);
1841 }
1842
1843 void connman_element_unregister_children(struct connman_element *element)
1844 {
1845         GNode *node;
1846
1847         DBG("element %p name %s", element, element->name);
1848
1849         g_static_rw_lock_writer_lock(&element_lock);
1850
1851         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1852
1853         if (node != NULL)
1854                 g_node_traverse(node, G_POST_ORDER,
1855                                 G_TRAVERSE_ALL, -1, remove_element, element);
1856
1857         g_static_rw_lock_writer_unlock(&element_lock);
1858 }
1859
1860 static gboolean update_element(GNode *node, gpointer user_data)
1861 {
1862         struct connman_element *element = node->data;
1863
1864         DBG("element %p name %s", element, element->name);
1865
1866         if (element->driver && element->driver->update)
1867                 element->driver->update(element);
1868
1869 #if 0
1870         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
1871                                 CONNMAN_MANAGER_INTERFACE, "ElementUpdated",
1872                                 DBUS_TYPE_OBJECT_PATH, &element->path,
1873                                                         DBUS_TYPE_INVALID);
1874 #endif
1875
1876         return FALSE;
1877 }
1878
1879 void connman_element_update(struct connman_element *element)
1880 {
1881         GNode *node;
1882
1883         DBG("element %p name %s", element, element->name);
1884
1885         g_static_rw_lock_reader_lock(&element_lock);
1886
1887         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1888
1889         if (node != NULL)
1890                 g_node_traverse(node, G_PRE_ORDER,
1891                                 G_TRAVERSE_ALL, -1, update_element, NULL);
1892
1893         g_static_rw_lock_reader_unlock(&element_lock);
1894 }
1895
1896 int connman_element_set_enabled(struct connman_element *element,
1897                                                         gboolean enabled)
1898 {
1899         if (element->enabled == enabled)
1900                 return 0;
1901
1902         element->enabled = enabled;
1903
1904         connman_element_update(element);
1905
1906         return 0;
1907 }
1908
1909 int __connman_element_init(DBusConnection *conn, const char *device)
1910 {
1911         struct connman_element *element;
1912
1913         DBG("conn %p", conn);
1914
1915         connection = dbus_connection_ref(conn);
1916         if (connection == NULL)
1917                 return -EIO;
1918
1919         device_filter = g_strdup(device);
1920
1921         g_static_rw_lock_writer_lock(&element_lock);
1922
1923         element = connman_element_create("root");
1924
1925         element->path = g_strdup("/");
1926         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1927
1928         create_default_properties(element);
1929
1930         element_root = g_node_new(element);
1931
1932         g_static_rw_lock_writer_unlock(&element_lock);
1933
1934         __connman_device_init();
1935
1936         return 0;
1937 }
1938
1939 static gboolean free_driver(GNode *node, gpointer data)
1940 {
1941         struct connman_element *element = node->data;
1942
1943         DBG("element %p name %s", element, element->name);
1944
1945         if (element->driver) {
1946                 if (element->driver->remove)
1947                         element->driver->remove(element);
1948
1949                 __connman_element_lock(element);
1950                 element->driver = NULL;
1951                 __connman_element_unlock(element);
1952         }
1953
1954         return FALSE;
1955 }
1956
1957 static gboolean free_node(GNode *node, gpointer data)
1958 {
1959         struct connman_element *element = node->data;
1960
1961         DBG("element %p name %s", element, element->name);
1962
1963         if (g_node_depth(node) > 1)
1964                 connman_element_unregister(element);
1965
1966         return FALSE;
1967 }
1968
1969 void __connman_element_cleanup(void)
1970 {
1971         DBG("");
1972
1973         __connman_device_cleanup();
1974
1975         g_static_rw_lock_writer_lock(&element_lock);
1976         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1977                                                         free_driver, NULL);
1978         g_static_rw_lock_writer_unlock(&element_lock);
1979
1980         g_static_rw_lock_writer_lock(&element_lock);
1981         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1982                                                         free_node, NULL);
1983         g_static_rw_lock_writer_unlock(&element_lock);
1984
1985         g_static_rw_lock_writer_lock(&element_lock);
1986         g_node_destroy(element_root);
1987         element_root = NULL;
1988         g_static_rw_lock_writer_unlock(&element_lock);
1989
1990         g_free(device_filter);
1991
1992         dbus_connection_unref(connection);
1993 }