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