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