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