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