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