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