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