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