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