Add Interface property for connections
[connman] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 static DBusConnection *connection;
36
37 static GNode *element_root = NULL;
38 static GSList *driver_list = NULL;
39 static gchar *device_filter = NULL;
40
41 static gboolean started = FALSE;
42
43 static struct {
44         enum connman_property_id id;
45         int type;
46         const char *name;
47         const void *value;
48 } propid_table[] = {
49         { CONNMAN_PROPERTY_ID_IPV4_METHOD,
50                 DBUS_TYPE_STRING, "IPv4.Method", "dhcp" },
51         { CONNMAN_PROPERTY_ID_IPV4_ADDRESS,
52                 DBUS_TYPE_STRING, "IPv4.Address" },
53         { CONNMAN_PROPERTY_ID_IPV4_NETMASK,
54                 DBUS_TYPE_STRING, "IPv4.Netmask" },
55         { CONNMAN_PROPERTY_ID_IPV4_GATEWAY,
56                 DBUS_TYPE_STRING, "IPv4.Gateway" },
57         { CONNMAN_PROPERTY_ID_IPV4_BROADCAST,
58                 DBUS_TYPE_STRING, "IPv4.Broadcast" },
59         { CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
60                 DBUS_TYPE_STRING, "IPv4.Nameserver" },
61
62         { CONNMAN_PROPERTY_ID_WIFI_SECURITY,
63                 DBUS_TYPE_STRING, "WiFi.Security" },
64         { CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE,
65                 DBUS_TYPE_STRING, "WiFi.Passphrase" },
66
67         { }
68 };
69
70 static int propid2type(enum connman_property_id id)
71 {
72         int i;
73
74         for (i = 0; propid_table[i].name; i++) {
75                 if (propid_table[i].id == id)
76                         return propid_table[i].type;
77         }
78
79         return DBUS_TYPE_INVALID;
80 }
81
82 static const char *propid2name(enum connman_property_id id)
83 {
84         int i;
85
86         for (i = 0; propid_table[i].name; i++) {
87                 if (propid_table[i].id == id)
88                         return propid_table[i].name;
89         }
90
91         return NULL;
92 }
93
94 static const char *type2string(enum connman_element_type type)
95 {
96         switch (type) {
97         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
98                 return "unknown";
99         case CONNMAN_ELEMENT_TYPE_ROOT:
100                 return "root";
101         case CONNMAN_ELEMENT_TYPE_PROFILE:
102                 return "profile";
103         case CONNMAN_ELEMENT_TYPE_DEVICE:
104                 return "device";
105         case CONNMAN_ELEMENT_TYPE_NETWORK:
106                 return "network";
107         case CONNMAN_ELEMENT_TYPE_SERVICE:
108                 return "service";
109         case CONNMAN_ELEMENT_TYPE_IPV4:
110                 return "ipv4";
111         case CONNMAN_ELEMENT_TYPE_IPV6:
112                 return "ipv6";
113         case CONNMAN_ELEMENT_TYPE_DHCP:
114                 return "dhcp";
115         case CONNMAN_ELEMENT_TYPE_BOOTP:
116                 return "bootp";
117         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
118                 return "zeroconf";
119         case CONNMAN_ELEMENT_TYPE_CONNECTION:
120                 return "connection";
121         }
122
123         return NULL;
124 }
125
126 static const char *subtype2string(enum connman_element_subtype type)
127 {
128         switch (type) {
129         case CONNMAN_ELEMENT_SUBTYPE_UNKNOWN:
130                 return "unknown";
131         case CONNMAN_ELEMENT_SUBTYPE_FAKE:
132                 return "fake";
133         case CONNMAN_ELEMENT_SUBTYPE_NETWORK:
134                 return "network";
135         case CONNMAN_ELEMENT_SUBTYPE_ETHERNET:
136                 return "ethernet";
137         case CONNMAN_ELEMENT_SUBTYPE_WIFI:
138                 return "wifi";
139         case CONNMAN_ELEMENT_SUBTYPE_WIMAX:
140                 return "wimax";
141         case CONNMAN_ELEMENT_SUBTYPE_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 append_filter {
614         enum connman_element_type type;
615         DBusMessageIter *iter;
616 };
617
618 static gboolean append_path(GNode *node, gpointer user_data)
619 {
620         struct connman_element *element = node->data;
621         struct append_filter *filter = user_data;
622
623         DBG("element %p name %s", element, element->name);
624
625         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
626                 return FALSE;
627
628         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
629                                         filter->type != element->type)
630                 return FALSE;
631
632         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
633                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
634                 return FALSE;
635
636         dbus_message_iter_append_basic(filter->iter,
637                                 DBUS_TYPE_OBJECT_PATH, &element->path);
638
639         return FALSE;
640 }
641
642 void __connman_element_list(struct connman_element *element,
643                                         enum connman_element_type type,
644                                                         DBusMessageIter *iter)
645 {
646         struct append_filter filter = { type, iter };
647         GNode *node;
648
649         DBG("");
650
651         if (element != NULL) {
652                 node = g_node_find(element_root, G_PRE_ORDER,
653                                                 G_TRAVERSE_ALL, element);
654                 if (node == NULL)
655                         return;
656         } else
657                 node = element_root;
658
659         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
660                                                 append_path, &filter);
661 }
662
663 struct count_data {
664         enum connman_element_type type;
665         int count;
666 };
667
668 static gboolean count_element(GNode *node, gpointer user_data)
669 {
670         struct connman_element *element = node->data;
671         struct count_data *data = user_data;
672
673         DBG("element %p name %s", element, element->name);
674
675         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
676                 return FALSE;
677
678         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
679                                         data->type != element->type)
680                 return FALSE;
681
682         data->count++;
683
684         return FALSE;
685 }
686
687 int __connman_element_count(struct connman_element *element,
688                                         enum connman_element_type type)
689 {
690         struct count_data data = { type, 0 };
691         GNode *node;
692
693         DBG("");
694
695         if (element != NULL) {
696                 node = g_node_find(element_root, G_PRE_ORDER,
697                                                 G_TRAVERSE_ALL, element);
698                 if (node == NULL)
699                         return 0;
700         } else
701                 node = element_root;
702
703         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
704                                                 count_element, &data);
705
706         return data.count;
707 }
708
709 static gint compare_priority(gconstpointer a, gconstpointer b)
710 {
711         const struct connman_driver *driver1 = a;
712         const struct connman_driver *driver2 = b;
713
714         return driver2->priority - driver1->priority;
715 }
716
717 static gboolean match_driver(struct connman_element *element,
718                                         struct connman_driver *driver)
719 {
720         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
721                 return FALSE;
722
723         if (element->type != driver->type &&
724                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
725                 return FALSE;
726
727         if (element->subtype == driver->subtype ||
728                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
729                 return TRUE;
730
731         return FALSE;
732 }
733
734 static void enable_element(struct connman_element *element)
735 {
736         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
737                 return;
738
739         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
740                 return;
741
742         if (element->driver && element->driver->enable) {
743                 if (element->driver->enable(element) == 0) {
744                         element->enabled = TRUE;
745                         emit_enabled_signal(connection, element);
746                 }
747         }
748 }
749
750 static gboolean probe_driver(GNode *node, gpointer data)
751 {
752         struct connman_element *element = node->data;
753         struct connman_driver *driver = data;
754
755         DBG("element %p name %s", element, element->name);
756
757         if (!element->driver && match_driver(element, driver) == TRUE) {
758                 if (driver->probe(element) < 0)
759                         return FALSE;
760
761                 __connman_element_lock(element);
762                 element->driver = driver;
763                 __connman_element_unlock(element);
764
765                 enable_element(element);
766         }
767
768         return FALSE;
769 }
770
771 void __connman_driver_rescan(struct connman_driver *driver)
772 {
773         DBG("driver %p name %s", driver, driver->name);
774
775         if (!driver->probe)
776                 return;
777
778         if (element_root != NULL)
779                 g_node_traverse(element_root, G_PRE_ORDER,
780                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
781 }
782
783 /**
784  * connman_driver_register:
785  * @driver: driver definition
786  *
787  * Register a new driver
788  *
789  * Returns: %0 on success
790  */
791 int connman_driver_register(struct connman_driver *driver)
792 {
793         DBG("driver %p name %s", driver, driver->name);
794
795         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
796                 return -EINVAL;
797
798         if (!driver->probe)
799                 return -EINVAL;
800
801         driver_list = g_slist_insert_sorted(driver_list, driver,
802                                                         compare_priority);
803
804         if (started == FALSE)
805                 return 0;
806
807         if (element_root != NULL)
808                 g_node_traverse(element_root, G_PRE_ORDER,
809                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
810
811         return 0;
812 }
813
814 static void disable_element(struct connman_element *element)
815 {
816         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
817                 return;
818
819         if (element->enabled == FALSE)
820                 return;
821
822         if (element->driver && element->driver->disable) {
823                 if (element->driver->disable(element) == 0) {
824                         element->enabled = FALSE;
825                         emit_enabled_signal(connection, element);
826                 }
827         }
828 }
829
830 static gboolean remove_driver(GNode *node, gpointer data)
831 {
832         struct connman_element *element = node->data;
833         struct connman_driver *driver = data;
834
835         DBG("element %p name %s", element, element->name);
836
837         if (element->driver == driver) {
838                 disable_element(element);
839
840                 if (driver->remove)
841                         driver->remove(element);
842
843                 __connman_element_lock(element);
844                 element->driver = NULL;
845                 __connman_element_unlock(element);
846         }
847
848         return FALSE;
849 }
850
851 /**
852  * connman_driver_unregister:
853  * @driver: driver definition
854  *
855  * Remove a previously registered driver
856  */
857 void connman_driver_unregister(struct connman_driver *driver)
858 {
859         DBG("driver %p name %s", driver, driver->name);
860
861         driver_list = g_slist_remove(driver_list, driver);
862
863         if (element_root != NULL)
864                 g_node_traverse(element_root, G_POST_ORDER,
865                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
866 }
867
868 /**
869  * connman_element_create:
870  * @name: element name
871  *
872  * Allocate a new element and assign the given #name to it. If the name
873  * is #NULL, it will be later on created based on the element type.
874  *
875  * Returns: a newly-allocated #connman_element structure
876  */
877 struct connman_element *connman_element_create(const char *name)
878 {
879         struct connman_element *element;
880
881         element = g_try_new0(struct connman_element, 1);
882         if (element == NULL)
883                 return NULL;
884
885         DBG("element %p", element);
886
887         element->refcount = 1;
888
889         element->name    = g_strdup(name);
890         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
891         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
892         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
893         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
894         element->index   = -1;
895         element->enabled = FALSE;
896
897         return element;
898 }
899
900 struct connman_element *connman_element_ref(struct connman_element *element)
901 {
902         DBG("element %p name %s refcount %d", element, element->name,
903                                 g_atomic_int_get(&element->refcount) + 1);
904
905         g_atomic_int_inc(&element->refcount);
906
907         return element;
908 }
909
910 static void free_properties(struct connman_element *element)
911 {
912         GSList *list;
913
914         DBG("element %p name %s", element, element->name);
915
916         __connman_element_lock(element);
917
918         for (list = element->properties; list; list = list->next) {
919                 struct connman_property *property = list->data;
920
921                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
922                         g_free(property->value);
923
924                 g_free(property->name);
925                 g_free(property);
926         }
927
928         g_slist_free(element->properties);
929
930         element->properties = NULL;
931
932         __connman_element_unlock(element);
933 }
934
935 void connman_element_unref(struct connman_element *element)
936 {
937         DBG("element %p name %s refcount %d", element, element->name,
938                                 g_atomic_int_get(&element->refcount) - 1);
939
940         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
941                 if (element->destruct)
942                         element->destruct(element);
943                 free_properties(element);
944                 g_free(element->ipv4.address);
945                 g_free(element->ipv4.netmask);
946                 g_free(element->ipv4.gateway);
947                 g_free(element->ipv4.network);
948                 g_free(element->ipv4.broadcast);
949                 g_free(element->ipv4.nameserver);
950                 g_free(element->devname);
951                 g_free(element->devpath);
952                 g_free(element->path);
953                 g_free(element->name);
954                 g_free(element);
955         }
956 }
957
958 int connman_element_add_static_property(struct connman_element *element,
959                                 const char *name, int type, const void *value)
960 {
961         struct connman_property *property;
962
963         DBG("element %p name %s", element, element->name);
964
965         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
966                 return -EINVAL;
967
968         property = g_try_new0(struct connman_property, 1);
969         if (property == NULL)
970                 return -ENOMEM;
971
972         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
973         property->id    = CONNMAN_PROPERTY_ID_INVALID;
974         property->name  = g_strdup(name);
975         property->type  = type;
976
977         DBG("name %s type %d value %p", name, type, value);
978
979         switch (type) {
980         case DBUS_TYPE_STRING:
981                 property->value = g_strdup(*((const char **) value));
982                 break;
983         case DBUS_TYPE_BYTE:
984                 property->value = g_try_malloc(1);
985                 if (property->value != NULL)
986                         memcpy(property->value, value, 1);
987                 break;
988         }
989
990         __connman_element_lock(element);
991         element->properties = g_slist_append(element->properties, property);
992         __connman_element_unlock(element);
993
994         return 0;
995 }
996
997 static void emit_property_changed(DBusConnection *conn,
998                                 struct connman_element *element,
999                                 const char *name, int type, const void *data)
1000 {
1001         DBusMessage *signal;
1002         DBusMessageIter entry, value;
1003         const char *iface, *sig;
1004
1005         DBG("conn %p", conn);
1006
1007         switch (element->type) {
1008         case CONNMAN_ELEMENT_TYPE_DEVICE:
1009                 iface = CONNMAN_DEVICE_INTERFACE;
1010                 break;
1011         case CONNMAN_ELEMENT_TYPE_NETWORK:
1012                 iface = CONNMAN_NETWORK_INTERFACE;
1013                 break;
1014         case CONNMAN_ELEMENT_TYPE_CONNECTION:
1015                 iface = CONNMAN_CONNECTION_INTERFACE;
1016                 break;
1017         default:
1018                 return;
1019         }
1020
1021         signal = dbus_message_new_signal(element->path,
1022                                                 iface, "PropertyChanged");
1023         if (signal == NULL)
1024                 return;
1025
1026         dbus_message_iter_init_append(signal, &entry);
1027
1028         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1029
1030         switch (type) {
1031         case DBUS_TYPE_STRING:
1032                 sig = DBUS_TYPE_STRING_AS_STRING;
1033                 break;
1034         case DBUS_TYPE_BYTE:
1035                 sig = DBUS_TYPE_BYTE_AS_STRING;
1036                 break;
1037         default:
1038                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1039                 break;
1040         }
1041
1042         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1043                                                         sig, &value);
1044         dbus_message_iter_append_basic(&value, type, data);
1045         dbus_message_iter_close_container(&entry, &value);
1046
1047         g_dbus_send_message(conn, signal);
1048 }
1049
1050 int connman_element_set_static_property(struct connman_element *element,
1051                                 const char *name, int type, const void *value)
1052 {
1053         GSList *list;
1054
1055         DBG("element %p name %s", element, element->name);
1056
1057         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1058                 return -EINVAL;
1059
1060         __connman_element_lock(element);
1061
1062         for (list = element->properties; list; list = list->next) {
1063                 struct connman_property *property = list->data;
1064
1065                 if (g_str_equal(property->name, name) == FALSE)
1066                         continue;
1067
1068                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1069                         continue;
1070
1071                 property->type = type;
1072                 g_free(property->value);
1073
1074                 switch (type) {
1075                 case DBUS_TYPE_STRING:
1076                         property->value = g_strdup(*((const char **) value));
1077                         break;
1078                 case DBUS_TYPE_BYTE:
1079                         property->value = g_try_malloc(1);
1080                         if (property->value != NULL)
1081                                 memcpy(property->value, value, 1);
1082                         break;
1083                 }
1084         }
1085
1086         __connman_element_unlock(element);
1087
1088         emit_property_changed(connection, element, name, type, value);
1089
1090         return 0;
1091 }
1092
1093 int connman_element_add_static_array_property(struct connman_element *element,
1094                         const char *name, int type, const void *value, int len)
1095 {
1096         struct connman_property *property;
1097
1098         DBG("element %p name %s", element, element->name);
1099
1100         if (type != DBUS_TYPE_BYTE)
1101                 return -EINVAL;
1102
1103         property = g_try_new0(struct connman_property, 1);
1104         if (property == NULL)
1105                 return -ENOMEM;
1106
1107         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1108         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1109         property->name    = g_strdup(name);
1110         property->type    = DBUS_TYPE_ARRAY;
1111         property->subtype = type;
1112
1113         DBG("name %s type %d value %p", name, type, value);
1114
1115         switch (type) {
1116         case DBUS_TYPE_BYTE:
1117                 property->value = g_try_malloc(len);
1118                 if (property->value != NULL) {
1119                         memcpy(property->value,
1120                                 *((const unsigned char **) value), len);
1121                         property->size = len;
1122                 }
1123                 break;
1124         }
1125
1126         __connman_element_lock(element);
1127         element->properties = g_slist_append(element->properties, property);
1128         __connman_element_unlock(element);
1129
1130         return 0;
1131 }
1132
1133 static void *get_reference_value(struct connman_element *element,
1134                                                 enum connman_property_id id)
1135 {
1136         GSList *list;
1137
1138         DBG("element %p name %s", element, element->name);
1139
1140         for (list = element->properties; list; list = list->next) {
1141                 struct connman_property *property = list->data;
1142
1143                 if (property->id != id)
1144                         continue;
1145
1146                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1147                         return property->value;
1148         }
1149
1150         if (element->parent == NULL)
1151                 return NULL;
1152
1153         return get_reference_value(element->parent, id);
1154 }
1155
1156 static void set_reference_properties(struct connman_element *element)
1157 {
1158         GSList *list;
1159
1160         DBG("element %p name %s", element, element->name);
1161
1162         for (list = element->properties; list; list = list->next) {
1163                 struct connman_property *property = list->data;
1164
1165                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1166                         continue;
1167
1168                 property->value = get_reference_value(element->parent,
1169                                                                 property->id);
1170         }
1171 }
1172
1173 static struct connman_property *create_property(struct connman_element *element,
1174                                                 enum connman_property_id id)
1175 {
1176         struct connman_property *property;
1177         GSList *list;
1178
1179         DBG("element %p name %s", element, element->name);
1180
1181         __connman_element_lock(element);
1182
1183         for (list = element->properties; list; list = list->next) {
1184                 property = list->data;
1185
1186                 if (property->id == id)
1187                         goto unlock;
1188         }
1189
1190         property = g_try_new0(struct connman_property, 1);
1191         if (property == NULL)
1192                 goto unlock;
1193
1194         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1195         property->id    = id;
1196         property->name  = g_strdup(propid2name(id));
1197         property->type  = propid2type(id);
1198
1199         if (property->name == NULL) {
1200                 g_free(property);
1201                 property = NULL;
1202                 goto unlock;
1203         }
1204
1205         element->properties = g_slist_append(element->properties, property);
1206
1207 unlock:
1208         __connman_element_unlock(element);
1209
1210         return property;
1211 }
1212
1213 static void create_default_properties(struct connman_element *element)
1214 {
1215         struct connman_property *property;
1216         int i;
1217
1218         DBG("element %p name %s", element, element->name);
1219
1220         for (i = 0; propid_table[i].name; i++) {
1221                 DBG("property %s", propid_table[i].name);
1222
1223                 property = create_property(element, propid_table[i].id);
1224
1225                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1226
1227                 if (propid_table[i].type != DBUS_TYPE_STRING)
1228                         continue;
1229
1230                 if (propid_table[i].value)
1231                         property->value = g_strdup(propid_table[i].value);
1232                 else
1233                         property->value = g_strdup("");
1234         }
1235 }
1236
1237 static int define_properties_valist(struct connman_element *element,
1238                                                                 va_list args)
1239 {
1240         enum connman_property_id id;
1241
1242         DBG("element %p name %s", element, element->name);
1243
1244         id = va_arg(args, enum connman_property_id);
1245
1246         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1247
1248                 DBG("property %d", id);
1249
1250                 create_property(element, id);
1251
1252                 id = va_arg(args, enum connman_property_id);
1253         }
1254
1255         return 0;
1256 }
1257
1258 /**
1259  * connman_element_define_properties:
1260  * @element: an element
1261  * @varargs: list of property identifiers
1262  *
1263  * Define the valid properties for an element.
1264  *
1265  * Returns: %0 on success
1266  */
1267 int connman_element_define_properties(struct connman_element *element, ...)
1268 {
1269         va_list args;
1270         int err;
1271
1272         DBG("element %p name %s", element, element->name);
1273
1274         va_start(args, element);
1275
1276         err = define_properties_valist(element, args);
1277
1278         va_end(args);
1279
1280         return err;
1281 }
1282
1283 int connman_element_create_property(struct connman_element *element,
1284                                                 const char *name, int type)
1285 {
1286         return -EIO;
1287 }
1288
1289 int connman_element_set_property(struct connman_element *element,
1290                                 enum connman_property_id id, const void *value)
1291 {
1292         switch (id) {
1293         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1294                 __connman_element_lock(element);
1295                 g_free(element->ipv4.address);
1296                 element->ipv4.address = g_strdup(*((const char **) value));
1297                 __connman_element_unlock(element);
1298                 break;
1299         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1300                 __connman_element_lock(element);
1301                 g_free(element->ipv4.netmask);
1302                 element->ipv4.netmask = g_strdup(*((const char **) value));
1303                 __connman_element_unlock(element);
1304                 break;
1305         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1306                 __connman_element_lock(element);
1307                 g_free(element->ipv4.gateway);
1308                 element->ipv4.gateway = g_strdup(*((const char **) value));
1309                 __connman_element_unlock(element);
1310                 break;
1311         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1312                 __connman_element_lock(element);
1313                 g_free(element->ipv4.broadcast);
1314                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1315                 __connman_element_unlock(element);
1316                 break;
1317         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1318                 __connman_element_lock(element);
1319                 g_free(element->ipv4.nameserver);
1320                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1321                 __connman_element_unlock(element);
1322                 break;
1323         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1324                 __connman_element_lock(element);
1325                 g_free(element->wifi.security);
1326                 element->wifi.security = g_strdup(*((const char **) value));
1327                 __connman_element_unlock(element);
1328                 break;
1329         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1330                 __connman_element_lock(element);
1331                 g_free(element->wifi.passphrase);
1332                 element->wifi.passphrase = g_strdup(*((const char **) value));
1333                 __connman_element_unlock(element);
1334                 break;
1335         default:
1336                 return -EINVAL;
1337         }
1338
1339         return 0;
1340 }
1341
1342 int connman_element_get_value(struct connman_element *element,
1343                                 enum connman_property_id id, void *value)
1344 {
1345         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1346                 return -EINVAL;
1347
1348         switch (id) {
1349         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1350                 if (element->ipv4.address == NULL)
1351                         return connman_element_get_value(element->parent,
1352                                                                 id, value);
1353                 __connman_element_lock(element);
1354                 *((char **) value) = element->ipv4.address;
1355                 __connman_element_unlock(element);
1356                 break;
1357         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1358                 if (element->ipv4.netmask == NULL)
1359                         return connman_element_get_value(element->parent,
1360                                                                 id, value);
1361                 __connman_element_lock(element);
1362                 *((char **) value) = element->ipv4.netmask;
1363                 __connman_element_unlock(element);
1364                 break;
1365         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1366                 if (element->ipv4.gateway == NULL)
1367                         return connman_element_get_value(element->parent,
1368                                                                 id, value);
1369                 __connman_element_lock(element);
1370                 *((char **) value) = element->ipv4.gateway;
1371                 __connman_element_unlock(element);
1372                 break;
1373         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1374                 if (element->ipv4.broadcast == NULL)
1375                         return connman_element_get_value(element->parent,
1376                                                                 id, value);
1377                 __connman_element_lock(element);
1378                 *((char **) value) = element->ipv4.broadcast;
1379                 __connman_element_unlock(element);
1380                 break;
1381         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1382                 if (element->ipv4.nameserver == NULL)
1383                         return connman_element_get_value(element->parent,
1384                                                                 id, value);
1385                 __connman_element_lock(element);
1386                 *((char **) value) = element->ipv4.nameserver;
1387                 __connman_element_unlock(element);
1388                 break;
1389         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1390                 if (element->wifi.security == NULL)
1391                         return connman_element_get_value(element->parent,
1392                                                                 id, value);
1393                 __connman_element_lock(element);
1394                 *((char **) value) = element->wifi.security;
1395                 __connman_element_unlock(element);
1396                 break;
1397         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1398                 if (element->wifi.passphrase == NULL)
1399                         return connman_element_get_value(element->parent,
1400                                                                 id, value);
1401                 __connman_element_lock(element);
1402                 *((char **) value) = element->wifi.passphrase;
1403                 __connman_element_unlock(element);
1404                 break;
1405         default:
1406                 return -EINVAL;
1407         }
1408
1409         return 0;
1410 }
1411
1412 gboolean connman_element_get_static_property(struct connman_element *element,
1413                                                 const char *name, void *value)
1414 {
1415         GSList *list;
1416         gboolean found = FALSE;
1417
1418         DBG("element %p name %s", element, element->name);
1419
1420         __connman_element_lock(element);
1421
1422         for (list = element->properties; list; list = list->next) {
1423                 struct connman_property *property = list->data;
1424
1425                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1426                         continue;
1427
1428                 if (g_str_equal(property->name, name) == TRUE) {
1429                         switch (property->type) {
1430                         case DBUS_TYPE_STRING:
1431                                 *((char **) value) = property->value;
1432                                 found = TRUE;
1433                                 break;
1434                         }
1435                         break;
1436                 }
1437         }
1438
1439         __connman_element_unlock(element);
1440
1441         return found;
1442 }
1443
1444 gboolean connman_element_get_static_array_property(struct connman_element *element,
1445                                         const char *name, void *value, int *len)
1446 {
1447         GSList *list;
1448         gboolean found = FALSE;
1449
1450         DBG("element %p name %s", element, element->name);
1451
1452         __connman_element_lock(element);
1453
1454         for (list = element->properties; list; list = list->next) {
1455                 struct connman_property *property = list->data;
1456
1457                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1458                         continue;
1459
1460                 if (g_str_equal(property->name, name) == TRUE) {
1461                         *((char **) value) = property->value;
1462                         *len = property->size;
1463                         found = TRUE;
1464                         break;
1465                 }
1466         }
1467
1468         __connman_element_unlock(element);
1469
1470         return found;
1471 }
1472
1473 gboolean connman_element_match_static_property(struct connman_element *element,
1474                                         const char *name, const void *value)
1475 {
1476         GSList *list;
1477         gboolean result = FALSE;
1478
1479         DBG("element %p name %s", element, element->name);
1480
1481         __connman_element_lock(element);
1482
1483         for (list = element->properties; list; list = list->next) {
1484                 struct connman_property *property = list->data;
1485
1486                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1487                         continue;
1488
1489                 if (g_str_equal(property->name, name) == FALSE)
1490                         continue;
1491
1492                 if (property->type == DBUS_TYPE_STRING)
1493                         result = g_str_equal(property->value,
1494                                                 *((const char **) value));
1495
1496                 if (result == TRUE)
1497                         break;
1498         }
1499
1500         __connman_element_unlock(element);
1501
1502         return result;
1503 }
1504
1505 static void append_networks(struct connman_element *element,
1506                                                 DBusMessageIter *entry)
1507 {
1508         DBusMessageIter value, iter;
1509         const char *key = "Networks";
1510
1511         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1512
1513         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1514                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1515                                                                 &value);
1516
1517         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1518                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1519         __connman_element_list(element, CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
1520         dbus_message_iter_close_container(&value, &iter);
1521
1522         dbus_message_iter_close_container(entry, &value);
1523 }
1524
1525 static void emit_networks_signal(DBusConnection *conn,
1526                                         struct connman_element *device)
1527 {
1528         DBusMessage *signal;
1529         DBusMessageIter entry;
1530
1531         DBG("conn %p", conn);
1532
1533         if (device == NULL)
1534                 return;
1535
1536         signal = dbus_message_new_signal(device->path,
1537                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1538         if (signal == NULL)
1539                 return;
1540
1541         dbus_message_iter_init_append(signal, &entry);
1542
1543         append_networks(device, &entry);
1544
1545         g_dbus_send_message(conn, signal);
1546 }
1547
1548 static void append_connections(DBusMessageIter *entry)
1549 {
1550         DBusMessageIter value, iter;
1551         const char *key = "Connections";
1552
1553         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1554
1555         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1556                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1557                                                                 &value);
1558
1559         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1560                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1561         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1562         dbus_message_iter_close_container(&value, &iter);
1563
1564         dbus_message_iter_close_container(entry, &value);
1565 }
1566
1567 static void emit_connections_signal(DBusConnection *conn)
1568 {
1569         DBusMessage *signal;
1570         DBusMessageIter entry;
1571
1572         DBG("conn %p", conn);
1573
1574         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1575                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1576         if (signal == NULL)
1577                 return;
1578
1579         dbus_message_iter_init_append(signal, &entry);
1580
1581         append_connections(&entry);
1582
1583         g_dbus_send_message(conn, signal);
1584 }
1585
1586 static void append_state(DBusMessageIter *entry, const char *state)
1587 {
1588         DBusMessageIter value;
1589         const char *key = "State";
1590
1591         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1592
1593         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1594                                         DBUS_TYPE_STRING_AS_STRING, &value);
1595         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1596         dbus_message_iter_close_container(entry, &value);
1597 }
1598
1599 static void emit_state_change(DBusConnection *conn, const char *state)
1600 {
1601         DBusMessage *signal;
1602         DBusMessageIter entry;
1603
1604         DBG("conn %p", conn);
1605
1606         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1607                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1608         if (signal == NULL)
1609                 return;
1610
1611         dbus_message_iter_init_append(signal, &entry);
1612
1613         append_state(&entry, state);
1614
1615         g_dbus_send_message(conn, signal);
1616 }
1617
1618 static void set_signal_strength(struct connman_element *connection)
1619 {
1620         struct connman_element *element = connection;
1621
1622         while (element != NULL) {
1623                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1624                         connection->strength = element->strength;
1625                         break;
1626                 }
1627
1628                 element = element->parent;
1629         }
1630 }
1631
1632 static void probe_element(struct connman_element *element)
1633 {
1634         GSList *list;
1635
1636         DBG("element %p name %s", element, element->name);
1637
1638         for (list = driver_list; list; list = list->next) {
1639                 struct connman_driver *driver = list->data;
1640
1641                 if (match_driver(element, driver) == FALSE)
1642                         continue;
1643
1644                 DBG("driver %p name %s", driver, driver->name);
1645
1646                 if (driver->probe(element) == 0) {
1647                         __connman_element_lock(element);
1648                         element->driver = driver;
1649                         __connman_element_unlock(element);
1650
1651                         enable_element(element);
1652                         break;
1653                 }
1654         }
1655 }
1656
1657 static void register_element(gpointer data, gpointer user_data)
1658 {
1659         struct connman_element *element = data;
1660         const gchar *basepath;
1661         GNode *node;
1662
1663         __connman_element_lock(element);
1664
1665         if (element->parent) {
1666                 node = g_node_find(element_root, G_PRE_ORDER,
1667                                         G_TRAVERSE_ALL, element->parent);
1668                 basepath = element->parent->path;
1669
1670                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1671                         element->subtype = element->parent->subtype;
1672         } else {
1673                 element->parent = element_root->data;
1674
1675                 node = element_root;
1676                 basepath = "";
1677         }
1678
1679         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1680
1681         set_reference_properties(element);
1682
1683         __connman_element_unlock(element);
1684
1685         DBG("element %p path %s", element, element->path);
1686
1687         __connman_element_load(element);
1688
1689         g_node_append_data(node, element);
1690
1691         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1692                 if (g_dbus_register_interface(connection, element->path,
1693                                         CONNMAN_NETWORK_INTERFACE,
1694                                         network_methods, element_signals,
1695                                         NULL, element, NULL) == FALSE)
1696                         connman_error("Failed to register %s network",
1697                                                                 element->path);
1698                 else
1699                         emit_networks_signal(connection, element->parent);
1700         }
1701
1702         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1703                 if (g_dbus_register_interface(connection, element->path,
1704                                         CONNMAN_CONNECTION_INTERFACE,
1705                                         connection_methods, element_signals,
1706                                         NULL, element, NULL) == FALSE)
1707                         connman_error("Failed to register %s connection",
1708                                                                 element->path);
1709                 else {
1710                         set_signal_strength(element);
1711                         emit_connections_signal(connection);
1712                         emit_state_change(connection, "online");
1713                 }
1714         }
1715
1716         __connman_element_store(element);
1717
1718         if (started == FALSE)
1719                 return;
1720
1721         probe_element(element);
1722 }
1723
1724 /**
1725  * connman_element_register:
1726  * @element: the element to register
1727  * @parent: the parent to register the element with
1728  *
1729  * Register an element with the core. It will be register under the given
1730  * parent of if %NULL is provided under the root element.
1731  *
1732  * Returns: %0 on success
1733  */
1734 int connman_element_register(struct connman_element *element,
1735                                         struct connman_element *parent)
1736 {
1737         DBG("element %p name %s parent %p", element, element->name, parent);
1738
1739         if (element->devname == NULL)
1740                 element->devname = g_strdup(element->name);
1741
1742         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1743                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1744                 if (g_pattern_match_simple(device_filter,
1745                                                 element->devname) == FALSE) {
1746                         DBG("ignoring %s [%s] device", element->name,
1747                                                         element->devname);
1748                         return -EPERM;
1749                 }
1750         }
1751
1752         if (connman_element_ref(element) == NULL)
1753                 return -EINVAL;
1754
1755         __connman_element_lock(element);
1756
1757         if (element->name == NULL) {
1758                 element->name = g_strdup(type2string(element->type));
1759                 if (element->name == NULL) {
1760                         __connman_element_unlock(element);
1761                         return -EINVAL;
1762                 }
1763         }
1764
1765         element->parent = parent;
1766
1767         __connman_element_unlock(element);
1768
1769         register_element(element, NULL);
1770
1771         return 0;
1772 }
1773
1774 static gboolean remove_element(GNode *node, gpointer user_data)
1775 {
1776         struct connman_element *element = node->data;
1777         struct connman_element *root = user_data;
1778
1779         DBG("element %p name %s", element, element->name);
1780
1781         if (element == root)
1782                 return FALSE;
1783
1784         if (node != NULL)
1785                 g_node_unlink(node);
1786
1787         if (element->driver) {
1788                 disable_element(element);
1789
1790                 if (element->driver->remove)
1791                         element->driver->remove(element);
1792
1793                 __connman_element_lock(element);
1794                 element->driver = NULL;
1795                 __connman_element_unlock(element);
1796         }
1797
1798         if (node != NULL)
1799                 g_node_destroy(node);
1800
1801         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1802                 if (__connman_element_count(NULL,
1803                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1804                         emit_state_change(connection, "offline");
1805                 emit_connections_signal(connection);
1806
1807                 g_dbus_unregister_interface(connection, element->path,
1808                                                 CONNMAN_CONNECTION_INTERFACE);
1809         }
1810
1811         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1812                 emit_networks_signal(connection, element->parent);
1813
1814                 g_dbus_unregister_interface(connection, element->path,
1815                                                 CONNMAN_NETWORK_INTERFACE);
1816         }
1817
1818         connman_element_unref(element);
1819
1820         return FALSE;
1821 }
1822
1823 void connman_element_unregister(struct connman_element *element)
1824 {
1825         GNode *node;
1826
1827         DBG("element %p name %s", element, element->name);
1828
1829         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1830
1831         if (node != NULL)
1832                 g_node_traverse(node, G_POST_ORDER,
1833                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1834 }
1835
1836 void connman_element_unregister_children(struct connman_element *element)
1837 {
1838         GNode *node;
1839
1840         DBG("element %p name %s", element, element->name);
1841
1842         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1843
1844         if (node != NULL)
1845                 g_node_traverse(node, G_POST_ORDER,
1846                                 G_TRAVERSE_ALL, -1, remove_element, element);
1847 }
1848
1849 static gboolean update_element(GNode *node, gpointer user_data)
1850 {
1851         struct connman_element *element = node->data;
1852         struct connman_element *root = user_data;
1853
1854         DBG("element %p name %s", element, element->name);
1855
1856         if (element->driver && element->driver->update)
1857                 element->driver->update(element);
1858
1859         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION &&
1860                                 root->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1861                 if (element->strength != root->strength) {
1862                         element->strength = root->strength;
1863                         emit_property_changed(connection, element, "Strength",
1864                                         DBUS_TYPE_BYTE, &element->strength);
1865                 }
1866         }
1867
1868         return FALSE;
1869 }
1870
1871 void connman_element_update(struct connman_element *element)
1872 {
1873         GNode *node;
1874
1875         DBG("element %p name %s", element, element->name);
1876
1877         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1878
1879         if (node != NULL)
1880                 g_node_traverse(node, G_PRE_ORDER,
1881                                 G_TRAVERSE_ALL, -1, update_element, element);
1882 }
1883
1884 int connman_element_set_enabled(struct connman_element *element,
1885                                                         gboolean enabled)
1886 {
1887         if (element->enabled == enabled)
1888                 return 0;
1889
1890         element->enabled = enabled;
1891
1892         emit_enabled_signal(connection, element);
1893
1894         return 0;
1895 }
1896
1897 int connman_element_set_scanning(struct connman_element *element,
1898                                                         gboolean scanning)
1899 {
1900         if (element->scanning == scanning)
1901                 return 0;
1902
1903         element->scanning = scanning;
1904
1905         emit_scanning_signal(connection, element);
1906
1907         return 0;
1908 }
1909
1910 int __connman_element_init(DBusConnection *conn, const char *device)
1911 {
1912         struct connman_element *element;
1913
1914         DBG("conn %p", conn);
1915
1916         connection = dbus_connection_ref(conn);
1917         if (connection == NULL)
1918                 return -EIO;
1919
1920         device_filter = g_strdup(device);
1921
1922         element = connman_element_create("root");
1923
1924         element->path = g_strdup("/");
1925         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1926
1927         create_default_properties(element);
1928
1929         element_root = g_node_new(element);
1930
1931         __connman_device_init();
1932         __connman_network_init();
1933
1934         return 0;
1935 }
1936
1937 static gboolean probe_node(GNode *node, gpointer data)
1938 {
1939         struct connman_element *element = node->data;
1940
1941         DBG("element %p name %s", element, element->name);
1942
1943         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1944                 return FALSE;
1945
1946         if (element->driver)
1947                 return FALSE;
1948
1949         probe_element(element);
1950
1951         return FALSE;
1952 }
1953
1954 void __connman_element_start(void)
1955 {
1956         DBG("");
1957
1958         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1959                                                         probe_node, NULL);
1960
1961         started = TRUE;
1962
1963         __connman_detect_init();
1964 }
1965
1966 void __connman_element_stop(void)
1967 {
1968         DBG("");
1969
1970         __connman_detect_cleanup();
1971 }
1972
1973 static gboolean free_driver(GNode *node, gpointer data)
1974 {
1975         struct connman_element *element = node->data;
1976
1977         DBG("element %p name %s", element, element->name);
1978
1979         if (element->driver) {
1980                 disable_element(element);
1981
1982                 if (element->driver->remove)
1983                         element->driver->remove(element);
1984
1985                 __connman_element_lock(element);
1986                 element->driver = NULL;
1987                 __connman_element_unlock(element);
1988         }
1989
1990         return FALSE;
1991 }
1992
1993 static gboolean free_node(GNode *node, gpointer data)
1994 {
1995         struct connman_element *element = node->data;
1996
1997         DBG("element %p name %s", element, element->name);
1998
1999         if (g_node_depth(node) > 1)
2000                 connman_element_unregister(element);
2001
2002         return FALSE;
2003 }
2004
2005 void __connman_element_cleanup(void)
2006 {
2007         DBG("");
2008
2009         __connman_network_cleanup();
2010         __connman_device_cleanup();
2011
2012         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2013                                                         free_driver, NULL);
2014
2015         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2016                                                         free_node, NULL);
2017
2018         g_node_destroy(element_root);
2019         element_root = NULL;
2020
2021         g_free(device_filter);
2022
2023         dbus_connection_unref(connection);
2024 }