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