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