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