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