Add skeleton for core connection driver
[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         if (filter->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
584                         __connman_network_has_driver(element->network) == FALSE)
585                 return FALSE;
586
587         dbus_message_iter_append_basic(filter->iter,
588                                 DBUS_TYPE_OBJECT_PATH, &element->path);
589
590         return FALSE;
591 }
592
593 void __connman_element_list(struct connman_element *element,
594                                         enum connman_element_type type,
595                                                         DBusMessageIter *iter)
596 {
597         struct append_filter filter = { type, iter };
598         GNode *node;
599
600         DBG("");
601
602         if (element != NULL) {
603                 node = g_node_find(element_root, G_PRE_ORDER,
604                                                 G_TRAVERSE_ALL, element);
605                 if (node == NULL)
606                         return;
607         } else
608                 node = element_root;
609
610         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
611                                                 append_path, &filter);
612 }
613
614 struct count_data {
615         enum connman_element_type type;
616         int count;
617 };
618
619 static gboolean count_element(GNode *node, gpointer user_data)
620 {
621         struct connman_element *element = node->data;
622         struct count_data *data = user_data;
623
624         DBG("element %p name %s", element, element->name);
625
626         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
627                 return FALSE;
628
629         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
630                                         data->type != element->type)
631                 return FALSE;
632
633         data->count++;
634
635         return FALSE;
636 }
637
638 int __connman_element_count(struct connman_element *element,
639                                         enum connman_element_type type)
640 {
641         struct count_data data = { type, 0 };
642         GNode *node;
643
644         DBG("");
645
646         if (element != NULL) {
647                 node = g_node_find(element_root, G_PRE_ORDER,
648                                                 G_TRAVERSE_ALL, element);
649                 if (node == NULL)
650                         return 0;
651         } else
652                 node = element_root;
653
654         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
655                                                 count_element, &data);
656
657         return data.count;
658 }
659
660 static gint compare_priority(gconstpointer a, gconstpointer b)
661 {
662         const struct connman_driver *driver1 = a;
663         const struct connman_driver *driver2 = b;
664
665         return driver2->priority - driver1->priority;
666 }
667
668 static gboolean match_driver(struct connman_element *element,
669                                         struct connman_driver *driver)
670 {
671         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
672                 return FALSE;
673
674         if (element->type != driver->type &&
675                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
676                 return FALSE;
677
678         if (element->subtype == driver->subtype ||
679                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
680                 return TRUE;
681
682         return FALSE;
683 }
684
685 static void enable_element(struct connman_element *element)
686 {
687         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
688                 return;
689
690         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
691                 return;
692
693         if (element->driver && element->driver->enable) {
694                 if (element->driver->enable(element) == 0) {
695                         element->enabled = TRUE;
696                         emit_enabled_signal(connection, element);
697                 }
698         }
699 }
700
701 static gboolean probe_driver(GNode *node, gpointer data)
702 {
703         struct connman_element *element = node->data;
704         struct connman_driver *driver = data;
705
706         DBG("element %p name %s", element, element->name);
707
708         if (!element->driver && match_driver(element, driver) == TRUE) {
709                 if (driver->probe(element) < 0)
710                         return FALSE;
711
712                 __connman_element_lock(element);
713                 element->driver = driver;
714                 __connman_element_unlock(element);
715
716                 enable_element(element);
717         }
718
719         return FALSE;
720 }
721
722 void __connman_driver_rescan(struct connman_driver *driver)
723 {
724         DBG("driver %p name %s", driver, driver->name);
725
726         if (!driver->probe)
727                 return;
728
729         if (element_root != NULL)
730                 g_node_traverse(element_root, G_PRE_ORDER,
731                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
732 }
733
734 /**
735  * connman_driver_register:
736  * @driver: driver definition
737  *
738  * Register a new driver
739  *
740  * Returns: %0 on success
741  */
742 int connman_driver_register(struct connman_driver *driver)
743 {
744         DBG("driver %p name %s", driver, driver->name);
745
746         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
747                 return -EINVAL;
748
749         if (!driver->probe)
750                 return -EINVAL;
751
752         driver_list = g_slist_insert_sorted(driver_list, driver,
753                                                         compare_priority);
754
755         if (started == FALSE)
756                 return 0;
757
758         if (element_root != NULL)
759                 g_node_traverse(element_root, G_PRE_ORDER,
760                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
761
762         return 0;
763 }
764
765 static void disable_element(struct connman_element *element)
766 {
767         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
768                 return;
769
770         if (element->enabled == FALSE)
771                 return;
772
773         if (element->driver && element->driver->disable) {
774                 if (element->driver->disable(element) == 0) {
775                         element->enabled = FALSE;
776                         emit_enabled_signal(connection, element);
777                 }
778         }
779 }
780
781 static gboolean remove_driver(GNode *node, gpointer data)
782 {
783         struct connman_element *element = node->data;
784         struct connman_driver *driver = data;
785
786         DBG("element %p name %s", element, element->name);
787
788         if (element->driver == driver) {
789                 disable_element(element);
790
791                 if (driver->remove)
792                         driver->remove(element);
793
794                 __connman_element_lock(element);
795                 element->driver = NULL;
796                 __connman_element_unlock(element);
797         }
798
799         return FALSE;
800 }
801
802 /**
803  * connman_driver_unregister:
804  * @driver: driver definition
805  *
806  * Remove a previously registered driver
807  */
808 void connman_driver_unregister(struct connman_driver *driver)
809 {
810         DBG("driver %p name %s", driver, driver->name);
811
812         driver_list = g_slist_remove(driver_list, driver);
813
814         if (element_root != NULL)
815                 g_node_traverse(element_root, G_POST_ORDER,
816                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
817 }
818
819 /**
820  * connman_element_create:
821  * @name: element name
822  *
823  * Allocate a new element and assign the given #name to it. If the name
824  * is #NULL, it will be later on created based on the element type.
825  *
826  * Returns: a newly-allocated #connman_element structure
827  */
828 struct connman_element *connman_element_create(const char *name)
829 {
830         struct connman_element *element;
831
832         element = g_try_new0(struct connman_element, 1);
833         if (element == NULL)
834                 return NULL;
835
836         DBG("element %p", element);
837
838         element->refcount = 1;
839
840         element->name    = g_strdup(name);
841         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
842         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
843         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
844         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
845         element->index   = -1;
846         element->enabled = FALSE;
847
848         return element;
849 }
850
851 struct connman_element *connman_element_ref(struct connman_element *element)
852 {
853         DBG("element %p name %s refcount %d", element, element->name,
854                                 g_atomic_int_get(&element->refcount) + 1);
855
856         g_atomic_int_inc(&element->refcount);
857
858         return element;
859 }
860
861 static void free_properties(struct connman_element *element)
862 {
863         GSList *list;
864
865         DBG("element %p name %s", element, element->name);
866
867         __connman_element_lock(element);
868
869         for (list = element->properties; list; list = list->next) {
870                 struct connman_property *property = list->data;
871
872                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
873                         g_free(property->value);
874
875                 g_free(property->name);
876                 g_free(property);
877         }
878
879         g_slist_free(element->properties);
880
881         element->properties = NULL;
882
883         __connman_element_unlock(element);
884 }
885
886 void connman_element_unref(struct connman_element *element)
887 {
888         DBG("element %p name %s refcount %d", element, element->name,
889                                 g_atomic_int_get(&element->refcount) - 1);
890
891         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
892                 if (element->destruct)
893                         element->destruct(element);
894                 free_properties(element);
895                 g_free(element->ipv4.address);
896                 g_free(element->ipv4.netmask);
897                 g_free(element->ipv4.gateway);
898                 g_free(element->ipv4.network);
899                 g_free(element->ipv4.broadcast);
900                 g_free(element->ipv4.nameserver);
901                 g_free(element->devname);
902                 g_free(element->devpath);
903                 g_free(element->path);
904                 g_free(element->name);
905                 g_free(element);
906         }
907 }
908
909 int connman_element_add_static_property(struct connman_element *element,
910                                 const char *name, int type, const void *value)
911 {
912         struct connman_property *property;
913
914         DBG("element %p name %s", element, element->name);
915
916         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
917                 return -EINVAL;
918
919         property = g_try_new0(struct connman_property, 1);
920         if (property == NULL)
921                 return -ENOMEM;
922
923         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
924         property->id    = CONNMAN_PROPERTY_ID_INVALID;
925         property->name  = g_strdup(name);
926         property->type  = type;
927
928         DBG("name %s type %d value %p", name, type, value);
929
930         switch (type) {
931         case DBUS_TYPE_STRING:
932                 property->value = g_strdup(*((const char **) value));
933                 break;
934         case DBUS_TYPE_BYTE:
935                 property->value = g_try_malloc(1);
936                 if (property->value != NULL)
937                         memcpy(property->value, value, 1);
938                 break;
939         }
940
941         __connman_element_lock(element);
942         element->properties = g_slist_append(element->properties, property);
943         __connman_element_unlock(element);
944
945         return 0;
946 }
947
948 static void emit_property_changed(DBusConnection *conn,
949                                 struct connman_element *element,
950                                 const char *name, int type, const void *data)
951 {
952         DBusMessage *signal;
953         DBusMessageIter entry, value;
954         const char *iface, *sig;
955
956         DBG("conn %p", conn);
957
958         switch (element->type) {
959         case CONNMAN_ELEMENT_TYPE_CONNECTION:
960                 iface = CONNMAN_CONNECTION_INTERFACE;
961                 break;
962         default:
963                 return;
964         }
965
966         signal = dbus_message_new_signal(element->path,
967                                                 iface, "PropertyChanged");
968         if (signal == NULL)
969                 return;
970
971         dbus_message_iter_init_append(signal, &entry);
972
973         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
974
975         switch (type) {
976         case DBUS_TYPE_STRING:
977                 sig = DBUS_TYPE_STRING_AS_STRING;
978                 break;
979         case DBUS_TYPE_BYTE:
980                 sig = DBUS_TYPE_BYTE_AS_STRING;
981                 break;
982         default:
983                 sig = DBUS_TYPE_VARIANT_AS_STRING;
984                 break;
985         }
986
987         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
988                                                         sig, &value);
989         dbus_message_iter_append_basic(&value, type, data);
990         dbus_message_iter_close_container(&entry, &value);
991
992         g_dbus_send_message(conn, signal);
993 }
994
995 int connman_element_set_static_property(struct connman_element *element,
996                                 const char *name, int type, const void *value)
997 {
998         GSList *list;
999
1000         DBG("element %p name %s", element, element->name);
1001
1002         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1003                 return -EINVAL;
1004
1005         __connman_element_lock(element);
1006
1007         for (list = element->properties; list; list = list->next) {
1008                 struct connman_property *property = list->data;
1009
1010                 if (g_str_equal(property->name, name) == FALSE)
1011                         continue;
1012
1013                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1014                         continue;
1015
1016                 property->type = type;
1017                 g_free(property->value);
1018
1019                 switch (type) {
1020                 case DBUS_TYPE_STRING:
1021                         property->value = g_strdup(*((const char **) value));
1022                         break;
1023                 case DBUS_TYPE_BYTE:
1024                         property->value = g_try_malloc(1);
1025                         if (property->value != NULL)
1026                                 memcpy(property->value, value, 1);
1027                         break;
1028                 }
1029         }
1030
1031         __connman_element_unlock(element);
1032
1033         emit_property_changed(connection, element, name, type, value);
1034
1035         return 0;
1036 }
1037
1038 int connman_element_add_static_array_property(struct connman_element *element,
1039                         const char *name, int type, const void *value, int len)
1040 {
1041         struct connman_property *property;
1042
1043         DBG("element %p name %s", element, element->name);
1044
1045         if (type != DBUS_TYPE_BYTE)
1046                 return -EINVAL;
1047
1048         property = g_try_new0(struct connman_property, 1);
1049         if (property == NULL)
1050                 return -ENOMEM;
1051
1052         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1053         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1054         property->name    = g_strdup(name);
1055         property->type    = DBUS_TYPE_ARRAY;
1056         property->subtype = type;
1057
1058         DBG("name %s type %d value %p", name, type, value);
1059
1060         switch (type) {
1061         case DBUS_TYPE_BYTE:
1062                 property->value = g_try_malloc(len);
1063                 if (property->value != NULL) {
1064                         memcpy(property->value,
1065                                 *((const unsigned char **) value), len);
1066                         property->size = len;
1067                 }
1068                 break;
1069         }
1070
1071         __connman_element_lock(element);
1072         element->properties = g_slist_append(element->properties, property);
1073         __connman_element_unlock(element);
1074
1075         return 0;
1076 }
1077
1078 static void *get_reference_value(struct connman_element *element,
1079                                                 enum connman_property_id id)
1080 {
1081         GSList *list;
1082
1083         DBG("element %p name %s", element, element->name);
1084
1085         for (list = element->properties; list; list = list->next) {
1086                 struct connman_property *property = list->data;
1087
1088                 if (property->id != id)
1089                         continue;
1090
1091                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1092                         return property->value;
1093         }
1094
1095         if (element->parent == NULL)
1096                 return NULL;
1097
1098         return get_reference_value(element->parent, id);
1099 }
1100
1101 static void set_reference_properties(struct connman_element *element)
1102 {
1103         GSList *list;
1104
1105         DBG("element %p name %s", element, element->name);
1106
1107         for (list = element->properties; list; list = list->next) {
1108                 struct connman_property *property = list->data;
1109
1110                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1111                         continue;
1112
1113                 property->value = get_reference_value(element->parent,
1114                                                                 property->id);
1115         }
1116 }
1117
1118 static struct connman_property *create_property(struct connman_element *element,
1119                                                 enum connman_property_id id)
1120 {
1121         struct connman_property *property;
1122         GSList *list;
1123
1124         DBG("element %p name %s", element, element->name);
1125
1126         __connman_element_lock(element);
1127
1128         for (list = element->properties; list; list = list->next) {
1129                 property = list->data;
1130
1131                 if (property->id == id)
1132                         goto unlock;
1133         }
1134
1135         property = g_try_new0(struct connman_property, 1);
1136         if (property == NULL)
1137                 goto unlock;
1138
1139         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1140         property->id    = id;
1141         property->name  = g_strdup(propid2name(id));
1142         property->type  = propid2type(id);
1143
1144         if (property->name == NULL) {
1145                 g_free(property);
1146                 property = NULL;
1147                 goto unlock;
1148         }
1149
1150         element->properties = g_slist_append(element->properties, property);
1151
1152 unlock:
1153         __connman_element_unlock(element);
1154
1155         return property;
1156 }
1157
1158 static void create_default_properties(struct connman_element *element)
1159 {
1160         struct connman_property *property;
1161         int i;
1162
1163         DBG("element %p name %s", element, element->name);
1164
1165         for (i = 0; propid_table[i].name; i++) {
1166                 DBG("property %s", propid_table[i].name);
1167
1168                 property = create_property(element, propid_table[i].id);
1169
1170                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1171
1172                 if (propid_table[i].type != DBUS_TYPE_STRING)
1173                         continue;
1174
1175                 if (propid_table[i].value)
1176                         property->value = g_strdup(propid_table[i].value);
1177                 else
1178                         property->value = g_strdup("");
1179         }
1180 }
1181
1182 static int define_properties_valist(struct connman_element *element,
1183                                                                 va_list args)
1184 {
1185         enum connman_property_id id;
1186
1187         DBG("element %p name %s", element, element->name);
1188
1189         id = va_arg(args, enum connman_property_id);
1190
1191         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1192
1193                 DBG("property %d", id);
1194
1195                 create_property(element, id);
1196
1197                 id = va_arg(args, enum connman_property_id);
1198         }
1199
1200         return 0;
1201 }
1202
1203 /**
1204  * connman_element_define_properties:
1205  * @element: an element
1206  * @varargs: list of property identifiers
1207  *
1208  * Define the valid properties for an element.
1209  *
1210  * Returns: %0 on success
1211  */
1212 int connman_element_define_properties(struct connman_element *element, ...)
1213 {
1214         va_list args;
1215         int err;
1216
1217         DBG("element %p name %s", element, element->name);
1218
1219         va_start(args, element);
1220
1221         err = define_properties_valist(element, args);
1222
1223         va_end(args);
1224
1225         return err;
1226 }
1227
1228 int connman_element_create_property(struct connman_element *element,
1229                                                 const char *name, int type)
1230 {
1231         return -EIO;
1232 }
1233
1234 int connman_element_set_property(struct connman_element *element,
1235                                 enum connman_property_id id, const void *value)
1236 {
1237         switch (id) {
1238         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1239                 __connman_element_lock(element);
1240                 g_free(element->ipv4.address);
1241                 element->ipv4.address = g_strdup(*((const char **) value));
1242                 __connman_element_unlock(element);
1243                 break;
1244         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1245                 __connman_element_lock(element);
1246                 g_free(element->ipv4.netmask);
1247                 element->ipv4.netmask = g_strdup(*((const char **) value));
1248                 __connman_element_unlock(element);
1249                 break;
1250         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1251                 __connman_element_lock(element);
1252                 g_free(element->ipv4.gateway);
1253                 element->ipv4.gateway = g_strdup(*((const char **) value));
1254                 __connman_element_unlock(element);
1255                 break;
1256         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1257                 __connman_element_lock(element);
1258                 g_free(element->ipv4.broadcast);
1259                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1260                 __connman_element_unlock(element);
1261                 break;
1262         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1263                 __connman_element_lock(element);
1264                 g_free(element->ipv4.nameserver);
1265                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1266                 __connman_element_unlock(element);
1267                 break;
1268         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1269                 __connman_element_lock(element);
1270                 g_free(element->wifi.security);
1271                 element->wifi.security = g_strdup(*((const char **) value));
1272                 __connman_element_unlock(element);
1273                 break;
1274         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1275                 __connman_element_lock(element);
1276                 g_free(element->wifi.passphrase);
1277                 element->wifi.passphrase = g_strdup(*((const char **) value));
1278                 __connman_element_unlock(element);
1279                 break;
1280         default:
1281                 return -EINVAL;
1282         }
1283
1284         return 0;
1285 }
1286
1287 int connman_element_get_value(struct connman_element *element,
1288                                 enum connman_property_id id, void *value)
1289 {
1290         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1291                 return -EINVAL;
1292
1293         switch (id) {
1294         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1295                 if (element->ipv4.address == NULL)
1296                         return connman_element_get_value(element->parent,
1297                                                                 id, value);
1298                 __connman_element_lock(element);
1299                 *((char **) value) = element->ipv4.address;
1300                 __connman_element_unlock(element);
1301                 break;
1302         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1303                 if (element->ipv4.netmask == NULL)
1304                         return connman_element_get_value(element->parent,
1305                                                                 id, value);
1306                 __connman_element_lock(element);
1307                 *((char **) value) = element->ipv4.netmask;
1308                 __connman_element_unlock(element);
1309                 break;
1310         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1311                 if (element->ipv4.gateway == NULL)
1312                         return connman_element_get_value(element->parent,
1313                                                                 id, value);
1314                 __connman_element_lock(element);
1315                 *((char **) value) = element->ipv4.gateway;
1316                 __connman_element_unlock(element);
1317                 break;
1318         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1319                 if (element->ipv4.broadcast == NULL)
1320                         return connman_element_get_value(element->parent,
1321                                                                 id, value);
1322                 __connman_element_lock(element);
1323                 *((char **) value) = element->ipv4.broadcast;
1324                 __connman_element_unlock(element);
1325                 break;
1326         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1327                 if (element->ipv4.nameserver == NULL)
1328                         return connman_element_get_value(element->parent,
1329                                                                 id, value);
1330                 __connman_element_lock(element);
1331                 *((char **) value) = element->ipv4.nameserver;
1332                 __connman_element_unlock(element);
1333                 break;
1334         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1335                 if (element->wifi.security == NULL)
1336                         return connman_element_get_value(element->parent,
1337                                                                 id, value);
1338                 __connman_element_lock(element);
1339                 *((char **) value) = element->wifi.security;
1340                 __connman_element_unlock(element);
1341                 break;
1342         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1343                 if (element->wifi.passphrase == NULL)
1344                         return connman_element_get_value(element->parent,
1345                                                                 id, value);
1346                 __connman_element_lock(element);
1347                 *((char **) value) = element->wifi.passphrase;
1348                 __connman_element_unlock(element);
1349                 break;
1350         default:
1351                 return -EINVAL;
1352         }
1353
1354         return 0;
1355 }
1356
1357 gboolean connman_element_get_static_property(struct connman_element *element,
1358                                                 const char *name, void *value)
1359 {
1360         GSList *list;
1361         gboolean found = FALSE;
1362
1363         DBG("element %p name %s", element, element->name);
1364
1365         __connman_element_lock(element);
1366
1367         for (list = element->properties; list; list = list->next) {
1368                 struct connman_property *property = list->data;
1369
1370                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1371                         continue;
1372
1373                 if (g_str_equal(property->name, name) == TRUE) {
1374                         switch (property->type) {
1375                         case DBUS_TYPE_STRING:
1376                                 *((char **) value) = property->value;
1377                                 found = TRUE;
1378                                 break;
1379                         }
1380                         break;
1381                 }
1382         }
1383
1384         __connman_element_unlock(element);
1385
1386         return found;
1387 }
1388
1389 gboolean connman_element_get_static_array_property(struct connman_element *element,
1390                                         const char *name, void *value, int *len)
1391 {
1392         GSList *list;
1393         gboolean found = FALSE;
1394
1395         DBG("element %p name %s", element, element->name);
1396
1397         __connman_element_lock(element);
1398
1399         for (list = element->properties; list; list = list->next) {
1400                 struct connman_property *property = list->data;
1401
1402                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1403                         continue;
1404
1405                 if (g_str_equal(property->name, name) == TRUE) {
1406                         *((char **) value) = property->value;
1407                         *len = property->size;
1408                         found = TRUE;
1409                         break;
1410                 }
1411         }
1412
1413         __connman_element_unlock(element);
1414
1415         return found;
1416 }
1417
1418 gboolean connman_element_match_static_property(struct connman_element *element,
1419                                         const char *name, const void *value)
1420 {
1421         GSList *list;
1422         gboolean result = FALSE;
1423
1424         DBG("element %p name %s", element, element->name);
1425
1426         __connman_element_lock(element);
1427
1428         for (list = element->properties; list; list = list->next) {
1429                 struct connman_property *property = list->data;
1430
1431                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1432                         continue;
1433
1434                 if (g_str_equal(property->name, name) == FALSE)
1435                         continue;
1436
1437                 if (property->type == DBUS_TYPE_STRING)
1438                         result = g_str_equal(property->value,
1439                                                 *((const char **) value));
1440
1441                 if (result == TRUE)
1442                         break;
1443         }
1444
1445         __connman_element_unlock(element);
1446
1447         return result;
1448 }
1449
1450 static void append_connections(DBusMessageIter *entry)
1451 {
1452         DBusMessageIter value, iter;
1453         const char *key = "Connections";
1454
1455         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1456
1457         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1458                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1459                                                                 &value);
1460
1461         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1462                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1463         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1464         dbus_message_iter_close_container(&value, &iter);
1465
1466         dbus_message_iter_close_container(entry, &value);
1467 }
1468
1469 static void emit_connections_signal(DBusConnection *conn)
1470 {
1471         DBusMessage *signal;
1472         DBusMessageIter entry;
1473
1474         DBG("conn %p", conn);
1475
1476         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1477                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1478         if (signal == NULL)
1479                 return;
1480
1481         dbus_message_iter_init_append(signal, &entry);
1482
1483         append_connections(&entry);
1484
1485         g_dbus_send_message(conn, signal);
1486 }
1487
1488 static void append_state(DBusMessageIter *entry, const char *state)
1489 {
1490         DBusMessageIter value;
1491         const char *key = "State";
1492
1493         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1494
1495         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1496                                         DBUS_TYPE_STRING_AS_STRING, &value);
1497         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1498         dbus_message_iter_close_container(entry, &value);
1499 }
1500
1501 static void emit_state_change(DBusConnection *conn, const char *state)
1502 {
1503         DBusMessage *signal;
1504         DBusMessageIter entry;
1505
1506         DBG("conn %p", conn);
1507
1508         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1509                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1510         if (signal == NULL)
1511                 return;
1512
1513         dbus_message_iter_init_append(signal, &entry);
1514
1515         append_state(&entry, state);
1516
1517         g_dbus_send_message(conn, signal);
1518 }
1519
1520 static void set_signal_strength(struct connman_element *connection)
1521 {
1522         struct connman_element *element = connection;
1523
1524         while (element != NULL) {
1525                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1526                         connection->strength = element->strength;
1527                         break;
1528                 }
1529
1530                 element = element->parent;
1531         }
1532 }
1533
1534 static void probe_element(struct connman_element *element)
1535 {
1536         GSList *list;
1537
1538         DBG("element %p name %s", element, element->name);
1539
1540         for (list = driver_list; list; list = list->next) {
1541                 struct connman_driver *driver = list->data;
1542
1543                 if (match_driver(element, driver) == FALSE)
1544                         continue;
1545
1546                 DBG("driver %p name %s", driver, driver->name);
1547
1548                 if (driver->probe(element) == 0) {
1549                         __connman_element_lock(element);
1550                         element->driver = driver;
1551                         __connman_element_unlock(element);
1552
1553                         enable_element(element);
1554                         break;
1555                 }
1556         }
1557 }
1558
1559 static void register_element(gpointer data, gpointer user_data)
1560 {
1561         struct connman_element *element = data;
1562         const gchar *basepath;
1563         GNode *node;
1564
1565         __connman_element_lock(element);
1566
1567         if (element->parent) {
1568                 node = g_node_find(element_root, G_PRE_ORDER,
1569                                         G_TRAVERSE_ALL, element->parent);
1570                 basepath = element->parent->path;
1571
1572                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1573                         element->subtype = element->parent->subtype;
1574         } else {
1575                 element->parent = element_root->data;
1576
1577                 node = element_root;
1578                 basepath = "";
1579         }
1580
1581         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1582
1583         set_reference_properties(element);
1584
1585         __connman_element_unlock(element);
1586
1587         DBG("element %p path %s", element, element->path);
1588
1589         g_node_append_data(node, element);
1590
1591         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1592                 if (g_dbus_register_interface(connection, element->path,
1593                                         CONNMAN_CONNECTION_INTERFACE,
1594                                         connection_methods, element_signals,
1595                                         NULL, element, NULL) == FALSE)
1596                         connman_error("Failed to register %s connection",
1597                                                                 element->path);
1598                 else {
1599                         set_signal_strength(element);
1600                         emit_connections_signal(connection);
1601                         emit_state_change(connection, "online");
1602                 }
1603         }
1604
1605         emit_element_signal(connection, "ElementAdded", 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         __connman_connection_init();
1806
1807         return 0;
1808 }
1809
1810 static gboolean probe_node(GNode *node, gpointer data)
1811 {
1812         struct connman_element *element = node->data;
1813
1814         DBG("element %p name %s", element, element->name);
1815
1816         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1817                 return FALSE;
1818
1819         if (element->driver)
1820                 return FALSE;
1821
1822         probe_element(element);
1823
1824         return FALSE;
1825 }
1826
1827 void __connman_element_start(void)
1828 {
1829         DBG("");
1830
1831         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1832                                                         probe_node, NULL);
1833
1834         started = TRUE;
1835
1836         __connman_detect_init();
1837 }
1838
1839 void __connman_element_stop(void)
1840 {
1841         DBG("");
1842
1843         __connman_detect_cleanup();
1844 }
1845
1846 static gboolean free_driver(GNode *node, gpointer data)
1847 {
1848         struct connman_element *element = node->data;
1849
1850         DBG("element %p name %s", element, element->name);
1851
1852         if (element->driver) {
1853                 disable_element(element);
1854
1855                 if (element->driver->remove)
1856                         element->driver->remove(element);
1857
1858                 __connman_element_lock(element);
1859                 element->driver = NULL;
1860                 __connman_element_unlock(element);
1861         }
1862
1863         return FALSE;
1864 }
1865
1866 static gboolean free_node(GNode *node, gpointer data)
1867 {
1868         struct connman_element *element = node->data;
1869
1870         DBG("element %p name %s", element, element->name);
1871
1872         if (g_node_depth(node) > 1)
1873                 connman_element_unregister(element);
1874
1875         return FALSE;
1876 }
1877
1878 void __connman_element_cleanup(void)
1879 {
1880         DBG("");
1881
1882         __connman_connection_cleanup();
1883         __connman_network_cleanup();
1884         __connman_device_cleanup();
1885
1886         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1887                                                         free_driver, NULL);
1888
1889         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1890                                                         free_node, NULL);
1891
1892         g_node_destroy(element_root);
1893         element_root = NULL;
1894
1895         g_free(device_filter);
1896
1897         dbus_connection_unref(connection);
1898 }