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