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