Add Scanning property to device objects
[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_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_bool_t scanning = FALSE;
515
516                 connman_dbus_dict_append_variant(&dict, "Scanning",
517                                                 DBUS_TYPE_BOOLEAN, &scanning);
518
519                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
520                                                                 NULL, &entry);
521                 append_networks(element, &entry);
522                 dbus_message_iter_close_container(&dict, &entry);
523         }
524
525         add_common_properties(element, &dict);
526
527         dbus_message_iter_close_container(&array, &dict);
528
529         return reply;
530 }
531
532 static DBusMessage *device_set_property(DBusConnection *conn,
533                                         DBusMessage *msg, void *data)
534 {
535         struct connman_element *element = data;
536         DBusMessageIter iter, value;
537         const char *name;
538
539         DBG("conn %p", conn);
540
541         if (dbus_message_iter_init(msg, &iter) == FALSE)
542                 return __connman_error_invalid_arguments(msg);
543
544         dbus_message_iter_get_basic(&iter, &name);
545         dbus_message_iter_next(&iter);
546         dbus_message_iter_recurse(&iter, &value);
547
548         if (__connman_security_check_privileges(msg) < 0)
549                 return __connman_error_permission_denied(msg);
550
551         if (g_str_equal(name, "Powered") == TRUE) {
552                 dbus_bool_t powered;
553
554                 dbus_message_iter_get_basic(&value, &powered);
555
556                 if (powered == TRUE)
557                         do_enable(conn, msg, element);
558                 else
559                         do_disable(conn, msg, element);
560         } else
561                 set_common_property(element, name, &value);
562
563         __connman_element_store(element);
564
565         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
566 }
567
568 static int parse_network_dict(DBusMessageIter *iter, const char **ssid,
569                                 const char **security, const char **passphrase)
570 {
571         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
572                 DBusMessageIter entry, value;
573                 const char *key;
574
575                 dbus_message_iter_recurse(iter, &entry);
576                 dbus_message_iter_get_basic(&entry, &key);
577
578                 dbus_message_iter_next(&entry);
579                 dbus_message_iter_recurse(&entry, &value);
580
581                 switch (dbus_message_iter_get_arg_type(&value)) {
582                 case DBUS_TYPE_STRING:
583                         if (g_str_equal(key, "WiFi.SSID") == TRUE)
584                                 dbus_message_iter_get_basic(&value, ssid);
585                         else if (g_str_equal(key, "WiFi.Security") == TRUE)
586                                 dbus_message_iter_get_basic(&value, security);
587                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
588                                 dbus_message_iter_get_basic(&value, passphrase);
589                         break;
590                 }
591
592                 dbus_message_iter_next(iter);
593         }
594
595         return 0;
596 }
597
598 static DBusMessage *device_create_network(DBusConnection *conn,
599                                         DBusMessage *msg, void *data)
600 {
601         struct connman_element *element = data;
602         struct connman_element *network;
603         DBusMessageIter iter, array;
604         const char *ssid = NULL, *security = NULL, *passphrase = NULL;
605
606         DBG("conn %p", conn);
607
608         if (dbus_message_iter_init(msg, &iter) == FALSE)
609                 return __connman_error_invalid_arguments(msg);
610
611         dbus_message_iter_recurse(&iter, &array);
612         parse_network_dict(&array, &ssid, &security, &passphrase);
613         if (ssid == NULL)
614                 return __connman_error_invalid_arguments(msg);
615
616         DBG("ssid %s security %s passphrase %s", ssid, security, passphrase);
617
618         network = connman_element_create(ssid);
619
620         network->type = CONNMAN_ELEMENT_TYPE_NETWORK;
621         network->index = element->index;
622
623         network->remember = TRUE;
624
625         connman_element_add_static_property(network, "Name",
626                                                 DBUS_TYPE_STRING, &ssid);
627
628         connman_element_add_static_array_property(element, "WiFi.SSID",
629                                         DBUS_TYPE_BYTE, &ssid, strlen(ssid));
630
631         network->wifi.security = g_strdup(security);
632         network->wifi.passphrase = g_strdup(passphrase);
633
634         connman_element_register(network, element);
635
636         return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &network->path,
637                                                         DBUS_TYPE_INVALID);
638 }
639
640 static DBusMessage *device_remove_network(DBusConnection *conn,
641                                         DBusMessage *msg, void *data)
642 {
643         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
644 }
645
646 static DBusMessage *network_get_properties(DBusConnection *conn,
647                                         DBusMessage *msg, void *data)
648 {
649         struct connman_element *element = data;
650         DBusMessage *reply;
651         DBusMessageIter array, dict;
652         const char *str;
653
654         DBG("conn %p", conn);
655
656         reply = dbus_message_new_method_return(msg);
657         if (reply == NULL)
658                 return NULL;
659
660         dbus_message_iter_init_append(reply, &array);
661
662         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
663                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
664                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
665                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
666
667         str = __connman_element_policy2string(element->policy);
668         if (str != NULL)
669                 connman_dbus_dict_append_variant(&dict, "Policy",
670                                                 DBUS_TYPE_STRING, &str);
671
672         connman_dbus_dict_append_variant(&dict, "Available",
673                                         DBUS_TYPE_BOOLEAN, &element->available);
674
675         connman_dbus_dict_append_variant(&dict, "Connected",
676                                         DBUS_TYPE_BOOLEAN, &element->enabled);
677
678         connman_dbus_dict_append_variant(&dict, "Remember",
679                                         DBUS_TYPE_BOOLEAN, &element->remember);
680
681         add_common_properties(element, &dict);
682
683         dbus_message_iter_close_container(&array, &dict);
684
685         return reply;
686 }
687
688 static DBusMessage *network_set_property(DBusConnection *conn,
689                                         DBusMessage *msg, void *data)
690 {
691         struct connman_element *element = data;
692         DBusMessageIter iter;
693         DBusMessageIter value;
694         const char *name;
695
696         DBG("conn %p", conn);
697
698         if (dbus_message_iter_init(msg, &iter) == FALSE)
699                 return __connman_error_invalid_arguments(msg);
700
701         dbus_message_iter_get_basic(&iter, &name);
702         dbus_message_iter_next(&iter);
703         dbus_message_iter_recurse(&iter, &value);
704
705         if (__connman_security_check_privileges(msg) < 0)
706                 return __connman_error_permission_denied(msg);
707
708         if (g_str_equal(name, "Remember") == TRUE) {
709                 dbus_message_iter_get_basic(&value, &element->remember);
710         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
711                 const char *str;
712
713                 dbus_message_iter_get_basic(&value, &str);
714                 g_free(element->wifi.passphrase);
715                 element->wifi.passphrase = g_strdup(str);
716         } else
717                 set_common_property(element, name, &value);
718
719         __connman_element_store(element);
720
721         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
722 }
723
724 static DBusMessage *connection_get_properties(DBusConnection *conn,
725                                         DBusMessage *msg, void *data)
726 {
727         struct connman_element *element = data;
728         DBusMessage *reply;
729         DBusMessageIter array, dict;
730         const char *str;
731
732         DBG("conn %p", conn);
733
734         reply = dbus_message_new_method_return(msg);
735         if (reply == NULL)
736                 return NULL;
737
738         dbus_message_iter_init_append(reply, &array);
739
740         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
741                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
742                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
743                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
744
745         str = subtype2string(element->subtype);
746         if (str != NULL)
747                 connman_dbus_dict_append_variant(&dict, "Type",
748                                                 DBUS_TYPE_STRING, &str);
749
750         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIFI ||
751                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_WIMAX)
752                 connman_dbus_dict_append_variant(&dict, "Strength",
753                                         DBUS_TYPE_BYTE, &element->strength);
754
755         connman_dbus_dict_append_variant(&dict, "Default",
756                                         DBUS_TYPE_BOOLEAN, &element->enabled);
757
758         add_common_properties(element, &dict);
759
760         dbus_message_iter_close_container(&array, &dict);
761
762         return reply;
763 }
764
765 static DBusMessage *connection_set_property(DBusConnection *conn,
766                                         DBusMessage *msg, void *data)
767 {
768         struct connman_element *element = data;
769         DBusMessageIter iter, value;
770         const char *name;
771
772         DBG("conn %p", conn);
773
774         if (dbus_message_iter_init(msg, &iter) == FALSE)
775                 return __connman_error_invalid_arguments(msg);
776
777         dbus_message_iter_get_basic(&iter, &name);
778         dbus_message_iter_next(&iter);
779         dbus_message_iter_recurse(&iter, &value);
780
781         if (__connman_security_check_privileges(msg) < 0)
782                 return __connman_error_permission_denied(msg);
783
784         if (g_str_equal(name, "Default") == TRUE) {
785                 dbus_bool_t enabled;
786
787                 dbus_message_iter_get_basic(&value, &enabled);
788
789                 if (enabled == TRUE)
790                         return do_enable(conn, msg, element);
791                 else
792                         return do_disable(conn, msg, element);
793         }
794
795         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
796 }
797
798 static GDBusMethodTable device_methods[] = {
799         { "GetProperties", "",      "a{sv}", device_get_properties },
800         { "SetProperty",   "sv",    "",      device_set_property   },
801         { "CreateNetwork", "a{sv}", "o",     device_create_network },
802         { "RemoveNetwork", "o",     "",      device_remove_network },
803         { "ProposeScan",   "",      "",      do_update             },
804         { },
805 };
806
807 static GDBusMethodTable network_methods[] = {
808         { "GetProperties", "",   "a{sv}", network_get_properties },
809         { "SetProperty",   "sv", "",      network_set_property   },
810         { "Connect",       "",   "",      do_enable              },
811         { "Disconnect",    "",   "",      do_disable             },
812         { },
813 };
814
815 static GDBusMethodTable connection_methods[] = {
816         { "GetProperties", "",   "a{sv}", connection_get_properties },
817         { "SetProperty",   "sv", "",      connection_set_property   },
818         { },
819 };
820
821 static GDBusSignalTable element_signals[] = {
822         { "PropertyChanged", "sv" },
823         { },
824 };
825
826 struct append_filter {
827         enum connman_element_type type;
828         DBusMessageIter *iter;
829 };
830
831 static gboolean append_path(GNode *node, gpointer user_data)
832 {
833         struct connman_element *element = node->data;
834         struct append_filter *filter = user_data;
835
836         DBG("element %p name %s", element, element->name);
837
838         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
839                 return FALSE;
840
841         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
842                                         filter->type != element->type)
843                 return FALSE;
844
845         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
846                         element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
847                 return FALSE;
848
849         dbus_message_iter_append_basic(filter->iter,
850                                 DBUS_TYPE_OBJECT_PATH, &element->path);
851
852         return FALSE;
853 }
854
855 void __connman_element_list(struct connman_element *element,
856                                         enum connman_element_type type,
857                                                         DBusMessageIter *iter)
858 {
859         struct append_filter filter = { type, iter };
860         GNode *node;
861
862         DBG("");
863
864         if (element != NULL) {
865                 node = g_node_find(element_root, G_PRE_ORDER,
866                                                 G_TRAVERSE_ALL, element);
867                 if (node == NULL)
868                         return;
869         } else
870                 node = element_root;
871
872         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
873                                                 append_path, &filter);
874 }
875
876 struct count_data {
877         enum connman_element_type type;
878         int count;
879 };
880
881 static gboolean count_element(GNode *node, gpointer user_data)
882 {
883         struct connman_element *element = node->data;
884         struct count_data *data = user_data;
885
886         DBG("element %p name %s", element, element->name);
887
888         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
889                 return FALSE;
890
891         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
892                                         data->type != element->type)
893                 return FALSE;
894
895         data->count++;
896
897         return FALSE;
898 }
899
900 int __connman_element_count(struct connman_element *element,
901                                         enum connman_element_type type)
902 {
903         struct count_data data = { type, 0 };
904         GNode *node;
905
906         DBG("");
907
908         if (element != NULL) {
909                 node = g_node_find(element_root, G_PRE_ORDER,
910                                                 G_TRAVERSE_ALL, element);
911                 if (node == NULL)
912                         return 0;
913         } else
914                 node = element_root;
915
916         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
917                                                 count_element, &data);
918
919         return data.count;
920 }
921
922 static gint compare_priority(gconstpointer a, gconstpointer b)
923 {
924         const struct connman_driver *driver1 = a;
925         const struct connman_driver *driver2 = b;
926
927         return driver2->priority - driver1->priority;
928 }
929
930 static gboolean match_driver(struct connman_element *element,
931                                         struct connman_driver *driver)
932 {
933         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
934                 return FALSE;
935
936         if (element->type != driver->type &&
937                         driver->type != CONNMAN_ELEMENT_TYPE_UNKNOWN)
938                 return FALSE;
939
940         if (element->subtype == driver->subtype ||
941                         driver->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
942                 return TRUE;
943
944         return FALSE;
945 }
946
947 static void enable_element(struct connman_element *element)
948 {
949         if (element->type != CONNMAN_ELEMENT_TYPE_DEVICE)
950                 return;
951
952         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
953                 return;
954
955         if (element->driver && element->driver->enable) {
956                 if (element->driver->enable(element) == 0) {
957                         element->enabled = TRUE;
958                         emit_enabled_signal(connection, element);
959                 }
960         }
961 }
962
963 static gboolean probe_driver(GNode *node, gpointer data)
964 {
965         struct connman_element *element = node->data;
966         struct connman_driver *driver = data;
967
968         DBG("element %p name %s", element, element->name);
969
970         if (!element->driver && match_driver(element, driver) == TRUE) {
971                 if (driver->probe(element) < 0)
972                         return FALSE;
973
974                 __connman_element_lock(element);
975                 element->driver = driver;
976                 __connman_element_unlock(element);
977
978                 enable_element(element);
979         }
980
981         return FALSE;
982 }
983
984 void __connman_driver_rescan(struct connman_driver *driver)
985 {
986         DBG("driver %p name %s", driver, driver->name);
987
988         if (!driver->probe)
989                 return;
990
991         if (element_root != NULL)
992                 g_node_traverse(element_root, G_PRE_ORDER,
993                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
994 }
995
996 /**
997  * connman_driver_register:
998  * @driver: driver definition
999  *
1000  * Register a new driver
1001  *
1002  * Returns: %0 on success
1003  */
1004 int connman_driver_register(struct connman_driver *driver)
1005 {
1006         DBG("driver %p name %s", driver, driver->name);
1007
1008         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
1009                 return -EINVAL;
1010
1011         if (!driver->probe)
1012                 return -EINVAL;
1013
1014         driver_list = g_slist_insert_sorted(driver_list, driver,
1015                                                         compare_priority);
1016
1017         if (element_root != NULL)
1018                 g_node_traverse(element_root, G_PRE_ORDER,
1019                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
1020
1021         return 0;
1022 }
1023
1024 static void disable_element(struct connman_element *element)
1025 {
1026         if (element->policy != CONNMAN_ELEMENT_POLICY_AUTO)
1027                 return;
1028
1029         if (element->enabled == FALSE)
1030                 return;
1031
1032         if (element->driver && element->driver->disable) {
1033                 if (element->driver->disable(element) == 0) {
1034                         element->enabled = FALSE;
1035                         emit_enabled_signal(connection, element);
1036                 }
1037         }
1038 }
1039
1040 static gboolean remove_driver(GNode *node, gpointer data)
1041 {
1042         struct connman_element *element = node->data;
1043         struct connman_driver *driver = data;
1044
1045         DBG("element %p name %s", element, element->name);
1046
1047         if (element->driver == driver) {
1048                 disable_element(element);
1049
1050                 if (driver->remove)
1051                         driver->remove(element);
1052
1053                 __connman_element_lock(element);
1054                 element->driver = NULL;
1055                 __connman_element_unlock(element);
1056         }
1057
1058         return FALSE;
1059 }
1060
1061 /**
1062  * connman_driver_unregister:
1063  * @driver: driver definition
1064  *
1065  * Remove a previously registered driver
1066  */
1067 void connman_driver_unregister(struct connman_driver *driver)
1068 {
1069         DBG("driver %p name %s", driver, driver->name);
1070
1071         driver_list = g_slist_remove(driver_list, driver);
1072
1073         if (element_root != NULL)
1074                 g_node_traverse(element_root, G_POST_ORDER,
1075                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
1076 }
1077
1078 /**
1079  * connman_element_create:
1080  * @name: element name
1081  *
1082  * Allocate a new element and assign the given #name to it. If the name
1083  * is #NULL, it will be later on created based on the element type.
1084  *
1085  * Returns: a newly-allocated #connman_element structure
1086  */
1087 struct connman_element *connman_element_create(const char *name)
1088 {
1089         struct connman_element *element;
1090
1091         element = g_try_new0(struct connman_element, 1);
1092         if (element == NULL)
1093                 return NULL;
1094
1095         DBG("element %p", element);
1096
1097         element->refcount = 1;
1098
1099         element->name    = g_strdup(name);
1100         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
1101         element->subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
1102         element->state   = CONNMAN_ELEMENT_STATE_CLOSED;
1103         element->policy  = CONNMAN_ELEMENT_POLICY_AUTO;
1104         element->index   = -1;
1105         element->enabled = FALSE;
1106
1107         return element;
1108 }
1109
1110 struct connman_element *connman_element_ref(struct connman_element *element)
1111 {
1112         DBG("element %p name %s refcount %d", element, element->name,
1113                                 g_atomic_int_get(&element->refcount) + 1);
1114
1115         g_atomic_int_inc(&element->refcount);
1116
1117         return element;
1118 }
1119
1120 static void free_properties(struct connman_element *element)
1121 {
1122         GSList *list;
1123
1124         DBG("element %p name %s", element, element->name);
1125
1126         __connman_element_lock(element);
1127
1128         for (list = element->properties; list; list = list->next) {
1129                 struct connman_property *property = list->data;
1130
1131                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1132                         g_free(property->value);
1133
1134                 g_free(property->name);
1135                 g_free(property);
1136         }
1137
1138         g_slist_free(element->properties);
1139
1140         element->properties = NULL;
1141
1142         __connman_element_unlock(element);
1143 }
1144
1145 void connman_element_unref(struct connman_element *element)
1146 {
1147         DBG("element %p name %s refcount %d", element, element->name,
1148                                 g_atomic_int_get(&element->refcount) - 1);
1149
1150         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
1151                 free_properties(element);
1152                 g_free(element->ipv4.address);
1153                 g_free(element->ipv4.netmask);
1154                 g_free(element->ipv4.gateway);
1155                 g_free(element->ipv4.network);
1156                 g_free(element->ipv4.broadcast);
1157                 g_free(element->ipv4.nameserver);
1158                 g_free(element->devname);
1159                 g_free(element->path);
1160                 g_free(element->name);
1161                 g_free(element);
1162         }
1163 }
1164
1165 int connman_element_add_static_property(struct connman_element *element,
1166                                 const char *name, int type, const void *value)
1167 {
1168         struct connman_property *property;
1169
1170         DBG("element %p name %s", element, element->name);
1171
1172         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1173                 return -EINVAL;
1174
1175         property = g_try_new0(struct connman_property, 1);
1176         if (property == NULL)
1177                 return -ENOMEM;
1178
1179         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
1180         property->id    = CONNMAN_PROPERTY_ID_INVALID;
1181         property->name  = g_strdup(name);
1182         property->type  = type;
1183
1184         DBG("name %s type %d value %p", name, type, value);
1185
1186         switch (type) {
1187         case DBUS_TYPE_STRING:
1188                 property->value = g_strdup(*((const char **) value));
1189                 break;
1190         case DBUS_TYPE_BYTE:
1191                 property->value = g_try_malloc(1);
1192                 if (property->value != NULL)
1193                         memcpy(property->value, value, 1);
1194                 break;
1195         }
1196
1197         __connman_element_lock(element);
1198         element->properties = g_slist_append(element->properties, property);
1199         __connman_element_unlock(element);
1200
1201         return 0;
1202 }
1203
1204 static void emit_property_changed(DBusConnection *conn,
1205                                 struct connman_element *element,
1206                                 const char *name, int type, const void *data)
1207 {
1208         DBusMessage *signal;
1209         DBusMessageIter entry, value;
1210         const char *iface, *sig;
1211
1212         DBG("conn %p", conn);
1213
1214         switch (element->type) {
1215         case CONNMAN_ELEMENT_TYPE_DEVICE:
1216                 iface = CONNMAN_DEVICE_INTERFACE;
1217                 break;
1218         case CONNMAN_ELEMENT_TYPE_NETWORK:
1219                 iface = CONNMAN_NETWORK_INTERFACE;
1220                 break;
1221         case CONNMAN_ELEMENT_TYPE_CONNECTION:
1222                 iface = CONNMAN_CONNECTION_INTERFACE;
1223                 break;
1224         default:
1225                 return;
1226         }
1227
1228         signal = dbus_message_new_signal(element->path,
1229                                                 iface, "PropertyChanged");
1230         if (signal == NULL)
1231                 return;
1232
1233         dbus_message_iter_init_append(signal, &entry);
1234
1235         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
1236
1237         switch (type) {
1238         case DBUS_TYPE_STRING:
1239                 sig = DBUS_TYPE_STRING_AS_STRING;
1240                 break;
1241         case DBUS_TYPE_BYTE:
1242                 sig = DBUS_TYPE_BYTE_AS_STRING;
1243                 break;
1244         default:
1245                 sig = DBUS_TYPE_VARIANT_AS_STRING;
1246                 break;
1247         }
1248
1249         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1250                                                         sig, &value);
1251         dbus_message_iter_append_basic(&value, type, data);
1252         dbus_message_iter_close_container(&entry, &value);
1253
1254         g_dbus_send_message(conn, signal);
1255 }
1256
1257 int connman_element_set_static_property(struct connman_element *element,
1258                                 const char *name, int type, const void *value)
1259 {
1260         GSList *list;
1261
1262         DBG("element %p name %s", element, element->name);
1263
1264         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
1265                 return -EINVAL;
1266
1267         __connman_element_lock(element);
1268
1269         for (list = element->properties; list; list = list->next) {
1270                 struct connman_property *property = list->data;
1271
1272                 if (g_str_equal(property->name, name) == FALSE)
1273                         continue;
1274
1275                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1276                         continue;
1277
1278                 property->type = type;
1279                 g_free(property->value);
1280
1281                 switch (type) {
1282                 case DBUS_TYPE_STRING:
1283                         property->value = g_strdup(*((const char **) value));
1284                         break;
1285                 case DBUS_TYPE_BYTE:
1286                         property->value = g_try_malloc(1);
1287                         if (property->value != NULL)
1288                                 memcpy(property->value, value, 1);
1289                         break;
1290                 }
1291         }
1292
1293         __connman_element_unlock(element);
1294
1295         emit_property_changed(connection, element, name, type, value);
1296
1297         return 0;
1298 }
1299
1300 int connman_element_add_static_array_property(struct connman_element *element,
1301                         const char *name, int type, const void *value, int len)
1302 {
1303         struct connman_property *property;
1304
1305         DBG("element %p name %s", element, element->name);
1306
1307         if (type != DBUS_TYPE_BYTE)
1308                 return -EINVAL;
1309
1310         property = g_try_new0(struct connman_property, 1);
1311         if (property == NULL)
1312                 return -ENOMEM;
1313
1314         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
1315         property->id      = CONNMAN_PROPERTY_ID_INVALID;
1316         property->name    = g_strdup(name);
1317         property->type    = DBUS_TYPE_ARRAY;
1318         property->subtype = type;
1319
1320         DBG("name %s type %d value %p", name, type, value);
1321
1322         switch (type) {
1323         case DBUS_TYPE_BYTE:
1324                 property->value = g_try_malloc(len);
1325                 if (property->value != NULL) {
1326                         memcpy(property->value,
1327                                 *((const unsigned char **) value), len);
1328                         property->size = len;
1329                 }
1330                 break;
1331         }
1332
1333         __connman_element_lock(element);
1334         element->properties = g_slist_append(element->properties, property);
1335         __connman_element_unlock(element);
1336
1337         return 0;
1338 }
1339
1340 static void *get_reference_value(struct connman_element *element,
1341                                                 enum connman_property_id id)
1342 {
1343         GSList *list;
1344
1345         DBG("element %p name %s", element, element->name);
1346
1347         for (list = element->properties; list; list = list->next) {
1348                 struct connman_property *property = list->data;
1349
1350                 if (property->id != id)
1351                         continue;
1352
1353                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1354                         return property->value;
1355         }
1356
1357         if (element->parent == NULL)
1358                 return NULL;
1359
1360         return get_reference_value(element->parent, id);
1361 }
1362
1363 static void set_reference_properties(struct connman_element *element)
1364 {
1365         GSList *list;
1366
1367         DBG("element %p name %s", element, element->name);
1368
1369         for (list = element->properties; list; list = list->next) {
1370                 struct connman_property *property = list->data;
1371
1372                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
1373                         continue;
1374
1375                 property->value = get_reference_value(element->parent,
1376                                                                 property->id);
1377         }
1378 }
1379
1380 static struct connman_property *create_property(struct connman_element *element,
1381                                                 enum connman_property_id id)
1382 {
1383         struct connman_property *property;
1384         GSList *list;
1385
1386         DBG("element %p name %s", element, element->name);
1387
1388         __connman_element_lock(element);
1389
1390         for (list = element->properties; list; list = list->next) {
1391                 property = list->data;
1392
1393                 if (property->id == id)
1394                         goto unlock;
1395         }
1396
1397         property = g_try_new0(struct connman_property, 1);
1398         if (property == NULL)
1399                 goto unlock;
1400
1401         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
1402         property->id    = id;
1403         property->name  = g_strdup(propid2name(id));
1404         property->type  = propid2type(id);
1405
1406         if (property->name == NULL) {
1407                 g_free(property);
1408                 property = NULL;
1409                 goto unlock;
1410         }
1411
1412         element->properties = g_slist_append(element->properties, property);
1413
1414 unlock:
1415         __connman_element_unlock(element);
1416
1417         return property;
1418 }
1419
1420 static void create_default_properties(struct connman_element *element)
1421 {
1422         struct connman_property *property;
1423         int i;
1424
1425         DBG("element %p name %s", element, element->name);
1426
1427         for (i = 0; propid_table[i].name; i++) {
1428                 DBG("property %s", propid_table[i].name);
1429
1430                 property = create_property(element, propid_table[i].id);
1431
1432                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
1433
1434                 if (propid_table[i].type != DBUS_TYPE_STRING)
1435                         continue;
1436
1437                 if (propid_table[i].value)
1438                         property->value = g_strdup(propid_table[i].value);
1439                 else
1440                         property->value = g_strdup("");
1441         }
1442 }
1443
1444 static int define_properties_valist(struct connman_element *element,
1445                                                                 va_list args)
1446 {
1447         enum connman_property_id id;
1448
1449         DBG("element %p name %s", element, element->name);
1450
1451         id = va_arg(args, enum connman_property_id);
1452
1453         while (id != CONNMAN_PROPERTY_ID_INVALID) {
1454
1455                 DBG("property %d", id);
1456
1457                 create_property(element, id);
1458
1459                 id = va_arg(args, enum connman_property_id);
1460         }
1461
1462         return 0;
1463 }
1464
1465 /**
1466  * connman_element_define_properties:
1467  * @element: an element
1468  * @varargs: list of property identifiers
1469  *
1470  * Define the valid properties for an element.
1471  *
1472  * Returns: %0 on success
1473  */
1474 int connman_element_define_properties(struct connman_element *element, ...)
1475 {
1476         va_list args;
1477         int err;
1478
1479         DBG("element %p name %s", element, element->name);
1480
1481         va_start(args, element);
1482
1483         err = define_properties_valist(element, args);
1484
1485         va_end(args);
1486
1487         return err;
1488 }
1489
1490 int connman_element_create_property(struct connman_element *element,
1491                                                 const char *name, int type)
1492 {
1493         return -EIO;
1494 }
1495
1496 int connman_element_set_property(struct connman_element *element,
1497                                 enum connman_property_id id, const void *value)
1498 {
1499         switch (id) {
1500         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1501                 __connman_element_lock(element);
1502                 g_free(element->ipv4.address);
1503                 element->ipv4.address = g_strdup(*((const char **) value));
1504                 __connman_element_unlock(element);
1505                 break;
1506         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1507                 __connman_element_lock(element);
1508                 g_free(element->ipv4.netmask);
1509                 element->ipv4.netmask = g_strdup(*((const char **) value));
1510                 __connman_element_unlock(element);
1511                 break;
1512         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1513                 __connman_element_lock(element);
1514                 g_free(element->ipv4.gateway);
1515                 element->ipv4.gateway = g_strdup(*((const char **) value));
1516                 __connman_element_unlock(element);
1517                 break;
1518         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1519                 __connman_element_lock(element);
1520                 g_free(element->ipv4.broadcast);
1521                 element->ipv4.broadcast = g_strdup(*((const char **) value));
1522                 __connman_element_unlock(element);
1523                 break;
1524         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1525                 __connman_element_lock(element);
1526                 g_free(element->ipv4.nameserver);
1527                 element->ipv4.nameserver = g_strdup(*((const char **) value));
1528                 __connman_element_unlock(element);
1529                 break;
1530         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1531                 __connman_element_lock(element);
1532                 g_free(element->wifi.security);
1533                 element->wifi.security = g_strdup(*((const char **) value));
1534                 __connman_element_unlock(element);
1535                 break;
1536         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1537                 __connman_element_lock(element);
1538                 g_free(element->wifi.passphrase);
1539                 element->wifi.passphrase = g_strdup(*((const char **) value));
1540                 __connman_element_unlock(element);
1541                 break;
1542         default:
1543                 return -EINVAL;
1544         }
1545
1546         return 0;
1547 }
1548
1549 int connman_element_get_value(struct connman_element *element,
1550                                 enum connman_property_id id, void *value)
1551 {
1552         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1553                 return -EINVAL;
1554
1555         switch (id) {
1556         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
1557                 if (element->ipv4.address == NULL)
1558                         return connman_element_get_value(element->parent,
1559                                                                 id, value);
1560                 __connman_element_lock(element);
1561                 *((char **) value) = element->ipv4.address;
1562                 __connman_element_unlock(element);
1563                 break;
1564         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1565                 if (element->ipv4.netmask == NULL)
1566                         return connman_element_get_value(element->parent,
1567                                                                 id, value);
1568                 __connman_element_lock(element);
1569                 *((char **) value) = element->ipv4.netmask;
1570                 __connman_element_unlock(element);
1571                 break;
1572         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1573                 if (element->ipv4.gateway == NULL)
1574                         return connman_element_get_value(element->parent,
1575                                                                 id, value);
1576                 __connman_element_lock(element);
1577                 *((char **) value) = element->ipv4.gateway;
1578                 __connman_element_unlock(element);
1579                 break;
1580         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1581                 if (element->ipv4.broadcast == NULL)
1582                         return connman_element_get_value(element->parent,
1583                                                                 id, value);
1584                 __connman_element_lock(element);
1585                 *((char **) value) = element->ipv4.broadcast;
1586                 __connman_element_unlock(element);
1587                 break;
1588         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1589                 if (element->ipv4.nameserver == NULL)
1590                         return connman_element_get_value(element->parent,
1591                                                                 id, value);
1592                 __connman_element_lock(element);
1593                 *((char **) value) = element->ipv4.nameserver;
1594                 __connman_element_unlock(element);
1595                 break;
1596         case CONNMAN_PROPERTY_ID_WIFI_SECURITY:
1597                 if (element->wifi.security == NULL)
1598                         return connman_element_get_value(element->parent,
1599                                                                 id, value);
1600                 __connman_element_lock(element);
1601                 *((char **) value) = element->wifi.security;
1602                 __connman_element_unlock(element);
1603                 break;
1604         case CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE:
1605                 if (element->wifi.passphrase == NULL)
1606                         return connman_element_get_value(element->parent,
1607                                                                 id, value);
1608                 __connman_element_lock(element);
1609                 *((char **) value) = element->wifi.passphrase;
1610                 __connman_element_unlock(element);
1611                 break;
1612         default:
1613                 return -EINVAL;
1614         }
1615
1616         return 0;
1617 }
1618
1619 gboolean connman_element_get_static_property(struct connman_element *element,
1620                                                 const char *name, void *value)
1621 {
1622         GSList *list;
1623         gboolean found = FALSE;
1624
1625         DBG("element %p name %s", element, element->name);
1626
1627         __connman_element_lock(element);
1628
1629         for (list = element->properties; list; list = list->next) {
1630                 struct connman_property *property = list->data;
1631
1632                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1633                         continue;
1634
1635                 if (g_str_equal(property->name, name) == TRUE) {
1636                         switch (property->type) {
1637                         case DBUS_TYPE_STRING:
1638                                 *((char **) value) = property->value;
1639                                 found = TRUE;
1640                                 break;
1641                         }
1642                         break;
1643                 }
1644         }
1645
1646         __connman_element_unlock(element);
1647
1648         return found;
1649 }
1650
1651 gboolean connman_element_get_static_array_property(struct connman_element *element,
1652                                         const char *name, void *value, int *len)
1653 {
1654         GSList *list;
1655         gboolean found = FALSE;
1656
1657         DBG("element %p name %s", element, element->name);
1658
1659         __connman_element_lock(element);
1660
1661         for (list = element->properties; list; list = list->next) {
1662                 struct connman_property *property = list->data;
1663
1664                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1665                         continue;
1666
1667                 if (g_str_equal(property->name, name) == TRUE) {
1668                         *((char **) value) = property->value;
1669                         *len = property->size;
1670                         found = TRUE;
1671                         break;
1672                 }
1673         }
1674
1675         __connman_element_unlock(element);
1676
1677         return found;
1678 }
1679
1680 gboolean connman_element_match_static_property(struct connman_element *element,
1681                                         const char *name, const void *value)
1682 {
1683         GSList *list;
1684         gboolean result = FALSE;
1685
1686         DBG("element %p name %s", element, element->name);
1687
1688         __connman_element_lock(element);
1689
1690         for (list = element->properties; list; list = list->next) {
1691                 struct connman_property *property = list->data;
1692
1693                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1694                         continue;
1695
1696                 if (g_str_equal(property->name, name) == FALSE)
1697                         continue;
1698
1699                 if (property->type == DBUS_TYPE_STRING)
1700                         result = g_str_equal(property->value,
1701                                                 *((const char **) value));
1702
1703                 if (result == TRUE)
1704                         break;
1705         }
1706
1707         __connman_element_unlock(element);
1708
1709         return result;
1710 }
1711
1712 static void append_devices(DBusMessageIter *entry)
1713 {
1714         DBusMessageIter value, iter;
1715         const char *key = "Devices";
1716
1717         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1718
1719         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1720                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1721                                                                 &value);
1722
1723         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1724                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1725         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
1726         dbus_message_iter_close_container(&value, &iter);
1727
1728         dbus_message_iter_close_container(entry, &value);
1729 }
1730
1731 static void emit_devices_signal(DBusConnection *conn)
1732 {
1733         DBusMessage *signal;
1734         DBusMessageIter entry;
1735
1736         DBG("conn %p", conn);
1737
1738         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1739                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1740         if (signal == NULL)
1741                 return;
1742
1743         dbus_message_iter_init_append(signal, &entry);
1744
1745         append_devices(&entry);
1746
1747         g_dbus_send_message(conn, signal);
1748 }
1749
1750 static void emit_networks_signal(DBusConnection *conn,
1751                                         struct connman_element *device)
1752 {
1753         DBusMessage *signal;
1754         DBusMessageIter entry;
1755
1756         DBG("conn %p", conn);
1757
1758         if (device == NULL)
1759                 return;
1760
1761         signal = dbus_message_new_signal(device->path,
1762                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1763         if (signal == NULL)
1764                 return;
1765
1766         dbus_message_iter_init_append(signal, &entry);
1767
1768         append_networks(device, &entry);
1769
1770         g_dbus_send_message(conn, signal);
1771 }
1772
1773 static void append_connections(DBusMessageIter *entry)
1774 {
1775         DBusMessageIter value, iter;
1776         const char *key = "Connections";
1777
1778         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1779
1780         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1781                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1782                                                                 &value);
1783
1784         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1785                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1786         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1787         dbus_message_iter_close_container(&value, &iter);
1788
1789         dbus_message_iter_close_container(entry, &value);
1790 }
1791
1792 static void emit_connections_signal(DBusConnection *conn)
1793 {
1794         DBusMessage *signal;
1795         DBusMessageIter entry;
1796
1797         DBG("conn %p", conn);
1798
1799         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1800                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1801         if (signal == NULL)
1802                 return;
1803
1804         dbus_message_iter_init_append(signal, &entry);
1805
1806         append_connections(&entry);
1807
1808         g_dbus_send_message(conn, signal);
1809 }
1810
1811 static void append_state(DBusMessageIter *entry, const char *state)
1812 {
1813         DBusMessageIter value;
1814         const char *key = "State";
1815
1816         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1817
1818         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1819                                         DBUS_TYPE_STRING_AS_STRING, &value);
1820         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1821         dbus_message_iter_close_container(entry, &value);
1822 }
1823
1824 static void emit_state_change(DBusConnection *conn, const char *state)
1825 {
1826         DBusMessage *signal;
1827         DBusMessageIter entry;
1828
1829         DBG("conn %p", conn);
1830
1831         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1832                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1833         if (signal == NULL)
1834                 return;
1835
1836         dbus_message_iter_init_append(signal, &entry);
1837
1838         append_state(&entry, state);
1839
1840         g_dbus_send_message(conn, signal);
1841 }
1842
1843 static void set_signal_strength(struct connman_element *connection)
1844 {
1845         struct connman_element *element = connection;
1846
1847         while (element != NULL) {
1848                 if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1849                         connection->strength = element->strength;
1850                         break;
1851                 }
1852
1853                 element = element->parent;
1854         }
1855 }
1856
1857 static void register_element(gpointer data, gpointer user_data)
1858 {
1859         struct connman_element *element = data;
1860         const gchar *basepath;
1861         GSList *list;
1862         GNode *node;
1863
1864         __connman_element_lock(element);
1865
1866         if (element->parent) {
1867                 node = g_node_find(element_root, G_PRE_ORDER,
1868                                         G_TRAVERSE_ALL, element->parent);
1869                 basepath = element->parent->path;
1870
1871                 if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_UNKNOWN)
1872                         element->subtype = element->parent->subtype;
1873         } else {
1874                 element->parent = element_root->data;
1875
1876                 node = element_root;
1877                 basepath = "";
1878         }
1879
1880         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1881
1882         set_reference_properties(element);
1883
1884         __connman_element_unlock(element);
1885
1886         DBG("element %p path %s", element, element->path);
1887
1888         __connman_element_load(element);
1889
1890         g_node_append_data(node, element);
1891
1892         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1893                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1894                 if (g_dbus_register_interface(connection, element->path,
1895                                         CONNMAN_DEVICE_INTERFACE,
1896                                         device_methods, element_signals,
1897                                         NULL, element, NULL) == FALSE)
1898                         connman_error("Failed to register %s device",
1899                                                                 element->path);
1900                 else
1901                         emit_devices_signal(connection);
1902         }
1903
1904         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
1905                 if (g_dbus_register_interface(connection, element->path,
1906                                         CONNMAN_NETWORK_INTERFACE,
1907                                         network_methods, element_signals,
1908                                         NULL, element, NULL) == FALSE)
1909                         connman_error("Failed to register %s network",
1910                                                                 element->path);
1911                 else
1912                         emit_networks_signal(connection, element->parent);
1913         }
1914
1915         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1916                 if (g_dbus_register_interface(connection, element->path,
1917                                         CONNMAN_CONNECTION_INTERFACE,
1918                                         connection_methods, element_signals,
1919                                         NULL, element, NULL) == FALSE)
1920                         connman_error("Failed to register %s connection",
1921                                                                 element->path);
1922                 else {
1923                         set_signal_strength(element);
1924                         emit_connections_signal(connection);
1925                         emit_state_change(connection, "online");
1926                 }
1927         }
1928
1929         __connman_element_store(element);
1930
1931         for (list = driver_list; list; list = list->next) {
1932                 struct connman_driver *driver = list->data;
1933
1934                 if (match_driver(element, driver) == FALSE)
1935                         continue;
1936
1937                 DBG("driver %p name %s", driver, driver->name);
1938
1939                 if (driver->probe(element) == 0) {
1940                         __connman_element_lock(element);
1941                         element->driver = driver;
1942                         __connman_element_unlock(element);
1943
1944                         enable_element(element);
1945                         break;
1946                 }
1947         }
1948 }
1949
1950 /**
1951  * connman_element_register:
1952  * @element: the element to register
1953  * @parent: the parent to register the element with
1954  *
1955  * Register an element with the core. It will be register under the given
1956  * parent of if %NULL is provided under the root element.
1957  *
1958  * Returns: %0 on success
1959  */
1960 int connman_element_register(struct connman_element *element,
1961                                         struct connman_element *parent)
1962 {
1963         DBG("element %p name %s parent %p", element, element->name, parent);
1964
1965         if (element->devname == NULL)
1966                 element->devname = g_strdup(element->name);
1967
1968         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
1969                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
1970                 if (g_pattern_match_simple(device_filter,
1971                                                 element->devname) == FALSE) {
1972                         DBG("ignoring %s [%s] device", element->name,
1973                                                         element->devname);
1974                         return -EPERM;
1975                 }
1976         }
1977
1978         if (connman_element_ref(element) == NULL)
1979                 return -EINVAL;
1980
1981         __connman_element_lock(element);
1982
1983         if (element->name == NULL) {
1984                 element->name = g_strdup(type2string(element->type));
1985                 if (element->name == NULL) {
1986                         __connman_element_unlock(element);
1987                         return -EINVAL;
1988                 }
1989         }
1990
1991         element->parent = parent;
1992
1993         __connman_element_unlock(element);
1994
1995         register_element(element, NULL);
1996
1997         return 0;
1998 }
1999
2000 static gboolean remove_element(GNode *node, gpointer user_data)
2001 {
2002         struct connman_element *element = node->data;
2003         struct connman_element *root = user_data;
2004
2005         DBG("element %p name %s", element, element->name);
2006
2007         if (element == root)
2008                 return FALSE;
2009
2010         if (element->driver) {
2011                 disable_element(element);
2012
2013                 if (element->driver->remove)
2014                         element->driver->remove(element);
2015
2016                 __connman_element_lock(element);
2017                 element->driver = NULL;
2018                 __connman_element_unlock(element);
2019         }
2020
2021         if (node != NULL) {
2022                 g_node_unlink(node);
2023                 g_node_destroy(node);
2024         }
2025
2026         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
2027                 if (__connman_element_count(NULL,
2028                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
2029                         emit_state_change(connection, "offline");
2030                 emit_connections_signal(connection);
2031
2032                 g_dbus_unregister_interface(connection, element->path,
2033                                                 CONNMAN_CONNECTION_INTERFACE);
2034         }
2035
2036         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2037                 emit_networks_signal(connection, element->parent);
2038
2039                 g_dbus_unregister_interface(connection, element->path,
2040                                                 CONNMAN_NETWORK_INTERFACE);
2041         }
2042
2043         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
2044                         element->subtype != CONNMAN_ELEMENT_SUBTYPE_NETWORK) {
2045                 emit_devices_signal(connection);
2046
2047                 g_dbus_unregister_interface(connection, element->path,
2048                                                 CONNMAN_DEVICE_INTERFACE);
2049         }
2050
2051         connman_element_unref(element);
2052
2053         return FALSE;
2054 }
2055
2056 void connman_element_unregister(struct connman_element *element)
2057 {
2058         GNode *node;
2059
2060         DBG("element %p name %s", element, element->name);
2061
2062         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2063
2064         if (node != NULL)
2065                 g_node_traverse(node, G_POST_ORDER,
2066                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
2067 }
2068
2069 void connman_element_unregister_children(struct connman_element *element)
2070 {
2071         GNode *node;
2072
2073         DBG("element %p name %s", element, element->name);
2074
2075         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2076
2077         if (node != NULL)
2078                 g_node_traverse(node, G_POST_ORDER,
2079                                 G_TRAVERSE_ALL, -1, remove_element, element);
2080 }
2081
2082 static gboolean update_element(GNode *node, gpointer user_data)
2083 {
2084         struct connman_element *element = node->data;
2085         struct connman_element *root = user_data;
2086
2087         DBG("element %p name %s", element, element->name);
2088
2089         if (element->driver && element->driver->update)
2090                 element->driver->update(element);
2091
2092         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION &&
2093                                 root->type == CONNMAN_ELEMENT_TYPE_NETWORK) {
2094                 if (element->strength != root->strength) {
2095                         element->strength = root->strength;
2096                         emit_property_changed(connection, element, "Strength",
2097                                         DBUS_TYPE_BYTE, &element->strength);
2098                 }
2099         }
2100
2101         return FALSE;
2102 }
2103
2104 void connman_element_update(struct connman_element *element)
2105 {
2106         GNode *node;
2107
2108         DBG("element %p name %s", element, element->name);
2109
2110         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
2111
2112         if (node != NULL)
2113                 g_node_traverse(node, G_PRE_ORDER,
2114                                 G_TRAVERSE_ALL, -1, update_element, element);
2115 }
2116
2117 int connman_element_set_enabled(struct connman_element *element,
2118                                                         gboolean enabled)
2119 {
2120         if (element->enabled == enabled)
2121                 return 0;
2122
2123         element->enabled = enabled;
2124
2125         emit_enabled_signal(connection, element);
2126
2127         return 0;
2128 }
2129
2130 int __connman_element_init(DBusConnection *conn, const char *device)
2131 {
2132         struct connman_element *element;
2133
2134         DBG("conn %p", conn);
2135
2136         connection = dbus_connection_ref(conn);
2137         if (connection == NULL)
2138                 return -EIO;
2139
2140         device_filter = g_strdup(device);
2141
2142         element = connman_element_create("root");
2143
2144         element->path = g_strdup("/");
2145         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
2146
2147         create_default_properties(element);
2148
2149         element_root = g_node_new(element);
2150
2151         __connman_device_init();
2152
2153         return 0;
2154 }
2155
2156 static gboolean free_driver(GNode *node, gpointer data)
2157 {
2158         struct connman_element *element = node->data;
2159
2160         DBG("element %p name %s", element, element->name);
2161
2162         if (element->driver) {
2163                 disable_element(element);
2164
2165                 if (element->driver->remove)
2166                         element->driver->remove(element);
2167
2168                 __connman_element_lock(element);
2169                 element->driver = NULL;
2170                 __connman_element_unlock(element);
2171         }
2172
2173         return FALSE;
2174 }
2175
2176 static gboolean free_node(GNode *node, gpointer data)
2177 {
2178         struct connman_element *element = node->data;
2179
2180         DBG("element %p name %s", element, element->name);
2181
2182         if (g_node_depth(node) > 1)
2183                 connman_element_unregister(element);
2184
2185         return FALSE;
2186 }
2187
2188 void __connman_element_cleanup(void)
2189 {
2190         DBG("");
2191
2192         __connman_device_cleanup();
2193
2194         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2195                                                         free_driver, NULL);
2196
2197         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2198                                                         free_node, NULL);
2199
2200         g_node_destroy(element_root);
2201         element_root = NULL;
2202
2203         g_free(device_filter);
2204
2205         dbus_connection_unref(connection);
2206 }