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