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