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