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