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