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