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