Add Device and Network property to connection interface
[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 const char *__connman_element_get_device(struct connman_element *element)
431 {
432         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
433                                                 element->device != NULL)
434                 return element->path;
435
436         if (element->parent == NULL)
437                 return NULL;
438
439         return __connman_element_get_device(element->parent);
440 }
441
442 const char *__connman_element_get_network(struct connman_element *element)
443 {
444         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
445                                                 element->network != NULL)
446                 return element->path;
447
448         if (element->parent == NULL)
449                 return NULL;
450
451         return __connman_element_get_network(element->parent);
452 }
453
454 static gint compare_priority(gconstpointer a, gconstpointer b)
455 {
456         const struct connman_driver *driver1 = a;
457         const struct connman_driver *driver2 = b;
458
459         return driver2->priority - driver1->priority;
460 }
461
462 static gboolean match_driver(struct connman_element *element,
463                                         struct connman_driver *driver)
464 {
465         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
466                 return FALSE;
467
468         if (element->type == driver->type ||
469                         driver->type == CONNMAN_ELEMENT_TYPE_UNKNOWN)
470                 return TRUE;
471
472         return FALSE;
473 }
474
475 static gboolean probe_driver(GNode *node, gpointer data)
476 {
477         struct connman_element *element = node->data;
478         struct connman_driver *driver = data;
479
480         DBG("element %p name %s", element, element->name);
481
482         if (!element->driver && match_driver(element, driver) == TRUE) {
483                 if (driver->probe(element) < 0)
484                         return FALSE;
485
486                 __connman_element_lock(element);
487                 element->driver = driver;
488                 __connman_element_unlock(element);
489         }
490
491         return FALSE;
492 }
493
494 void __connman_driver_rescan(struct connman_driver *driver)
495 {
496         DBG("driver %p name %s", driver, driver->name);
497
498         if (!driver->probe)
499                 return;
500
501         if (element_root != NULL)
502                 g_node_traverse(element_root, G_PRE_ORDER,
503                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
504 }
505
506 /**
507  * connman_driver_register:
508  * @driver: driver definition
509  *
510  * Register a new driver
511  *
512  * Returns: %0 on success
513  */
514 int connman_driver_register(struct connman_driver *driver)
515 {
516         DBG("driver %p name %s", driver, driver->name);
517
518         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
519                 return -EINVAL;
520
521         if (!driver->probe)
522                 return -EINVAL;
523
524         driver_list = g_slist_insert_sorted(driver_list, driver,
525                                                         compare_priority);
526
527         if (started == FALSE)
528                 return 0;
529
530         if (element_root != NULL)
531                 g_node_traverse(element_root, G_PRE_ORDER,
532                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
533
534         return 0;
535 }
536
537 static gboolean remove_driver(GNode *node, gpointer data)
538 {
539         struct connman_element *element = node->data;
540         struct connman_driver *driver = data;
541
542         DBG("element %p name %s", element, element->name);
543
544         if (element->driver == driver) {
545                 if (driver->remove)
546                         driver->remove(element);
547
548                 __connman_element_lock(element);
549                 element->driver = NULL;
550                 __connman_element_unlock(element);
551         }
552
553         return FALSE;
554 }
555
556 /**
557  * connman_driver_unregister:
558  * @driver: driver definition
559  *
560  * Remove a previously registered driver
561  */
562 void connman_driver_unregister(struct connman_driver *driver)
563 {
564         DBG("driver %p name %s", driver, driver->name);
565
566         driver_list = g_slist_remove(driver_list, driver);
567
568         if (element_root != NULL)
569                 g_node_traverse(element_root, G_POST_ORDER,
570                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
571 }
572
573 /**
574  * connman_element_create:
575  * @name: element name
576  *
577  * Allocate a new element and assign the given #name to it. If the name
578  * is #NULL, it will be later on created based on the element type.
579  *
580  * Returns: a newly-allocated #connman_element structure
581  */
582 struct connman_element *connman_element_create(const char *name)
583 {
584         struct connman_element *element;
585
586         element = g_try_new0(struct connman_element, 1);
587         if (element == NULL)
588                 return NULL;
589
590         DBG("element %p", element);
591
592         element->refcount = 1;
593
594         element->name    = g_strdup(name);
595         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
596         element->index   = -1;
597         element->enabled = FALSE;
598
599         return element;
600 }
601
602 struct connman_element *connman_element_ref(struct connman_element *element)
603 {
604         DBG("element %p name %s refcount %d", element, element->name,
605                                 g_atomic_int_get(&element->refcount) + 1);
606
607         g_atomic_int_inc(&element->refcount);
608
609         return element;
610 }
611
612 static void free_properties(struct connman_element *element)
613 {
614         GSList *list;
615
616         DBG("element %p name %s", element, element->name);
617
618         __connman_element_lock(element);
619
620         for (list = element->properties; list; list = list->next) {
621                 struct connman_property *property = list->data;
622
623                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
624                         g_free(property->value);
625
626                 g_free(property->name);
627                 g_free(property);
628         }
629
630         g_slist_free(element->properties);
631
632         element->properties = NULL;
633
634         __connman_element_unlock(element);
635 }
636
637 void connman_element_unref(struct connman_element *element)
638 {
639         DBG("element %p name %s refcount %d", element, element->name,
640                                 g_atomic_int_get(&element->refcount) - 1);
641
642         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
643                 if (element->destruct)
644                         element->destruct(element);
645                 free_properties(element);
646                 g_free(element->ipv4.address);
647                 g_free(element->ipv4.netmask);
648                 g_free(element->ipv4.gateway);
649                 g_free(element->ipv4.network);
650                 g_free(element->ipv4.broadcast);
651                 g_free(element->ipv4.nameserver);
652                 g_free(element->devname);
653                 g_free(element->path);
654                 g_free(element->name);
655                 g_free(element);
656         }
657 }
658
659 int connman_element_add_static_property(struct connman_element *element,
660                                 const char *name, int type, const void *value)
661 {
662         struct connman_property *property;
663
664         DBG("element %p name %s", element, element->name);
665
666         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
667                 return -EINVAL;
668
669         property = g_try_new0(struct connman_property, 1);
670         if (property == NULL)
671                 return -ENOMEM;
672
673         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
674         property->id    = CONNMAN_PROPERTY_ID_INVALID;
675         property->name  = g_strdup(name);
676         property->type  = type;
677
678         DBG("name %s type %d value %p", name, type, value);
679
680         switch (type) {
681         case DBUS_TYPE_STRING:
682                 property->value = g_strdup(*((const char **) value));
683                 break;
684         case DBUS_TYPE_BYTE:
685                 property->value = g_try_malloc(1);
686                 if (property->value != NULL)
687                         memcpy(property->value, value, 1);
688                 break;
689         }
690
691         __connman_element_lock(element);
692         element->properties = g_slist_append(element->properties, property);
693         __connman_element_unlock(element);
694
695         return 0;
696 }
697
698 int connman_element_set_static_property(struct connman_element *element,
699                                 const char *name, int type, const void *value)
700 {
701         GSList *list;
702
703         DBG("element %p name %s", element, element->name);
704
705         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
706                 return -EINVAL;
707
708         __connman_element_lock(element);
709
710         for (list = element->properties; list; list = list->next) {
711                 struct connman_property *property = list->data;
712
713                 if (g_str_equal(property->name, name) == FALSE)
714                         continue;
715
716                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
717                         continue;
718
719                 property->type = type;
720                 g_free(property->value);
721
722                 switch (type) {
723                 case DBUS_TYPE_STRING:
724                         property->value = g_strdup(*((const char **) value));
725                         break;
726                 case DBUS_TYPE_BYTE:
727                         property->value = g_try_malloc(1);
728                         if (property->value != NULL)
729                                 memcpy(property->value, value, 1);
730                         break;
731                 }
732         }
733
734         __connman_element_unlock(element);
735
736         return 0;
737 }
738
739 int connman_element_add_static_array_property(struct connman_element *element,
740                         const char *name, int type, const void *value, int len)
741 {
742         struct connman_property *property;
743
744         DBG("element %p name %s", element, element->name);
745
746         if (type != DBUS_TYPE_BYTE)
747                 return -EINVAL;
748
749         property = g_try_new0(struct connman_property, 1);
750         if (property == NULL)
751                 return -ENOMEM;
752
753         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
754         property->id      = CONNMAN_PROPERTY_ID_INVALID;
755         property->name    = g_strdup(name);
756         property->type    = DBUS_TYPE_ARRAY;
757         property->subtype = type;
758
759         DBG("name %s type %d value %p", name, type, value);
760
761         switch (type) {
762         case DBUS_TYPE_BYTE:
763                 property->value = g_try_malloc(len);
764                 if (property->value != NULL) {
765                         memcpy(property->value,
766                                 *((const unsigned char **) value), len);
767                         property->size = len;
768                 }
769                 break;
770         }
771
772         __connman_element_lock(element);
773         element->properties = g_slist_append(element->properties, property);
774         __connman_element_unlock(element);
775
776         return 0;
777 }
778
779 static void *get_reference_value(struct connman_element *element,
780                                                 enum connman_property_id id)
781 {
782         GSList *list;
783
784         DBG("element %p name %s", element, element->name);
785
786         for (list = element->properties; list; list = list->next) {
787                 struct connman_property *property = list->data;
788
789                 if (property->id != id)
790                         continue;
791
792                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
793                         return property->value;
794         }
795
796         if (element->parent == NULL)
797                 return NULL;
798
799         return get_reference_value(element->parent, id);
800 }
801
802 static void set_reference_properties(struct connman_element *element)
803 {
804         GSList *list;
805
806         DBG("element %p name %s", element, element->name);
807
808         for (list = element->properties; list; list = list->next) {
809                 struct connman_property *property = list->data;
810
811                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
812                         continue;
813
814                 property->value = get_reference_value(element->parent,
815                                                                 property->id);
816         }
817 }
818
819 static struct connman_property *create_property(struct connman_element *element,
820                                                 enum connman_property_id id)
821 {
822         struct connman_property *property;
823         GSList *list;
824
825         DBG("element %p name %s", element, element->name);
826
827         __connman_element_lock(element);
828
829         for (list = element->properties; list; list = list->next) {
830                 property = list->data;
831
832                 if (property->id == id)
833                         goto unlock;
834         }
835
836         property = g_try_new0(struct connman_property, 1);
837         if (property == NULL)
838                 goto unlock;
839
840         property->flags = CONNMAN_PROPERTY_FLAG_REFERENCE;
841         property->id    = id;
842         property->name  = g_strdup(propid2name(id));
843         property->type  = propid2type(id);
844
845         if (property->name == NULL) {
846                 g_free(property);
847                 property = NULL;
848                 goto unlock;
849         }
850
851         element->properties = g_slist_append(element->properties, property);
852
853 unlock:
854         __connman_element_unlock(element);
855
856         return property;
857 }
858
859 static void create_default_properties(struct connman_element *element)
860 {
861         struct connman_property *property;
862         int i;
863
864         DBG("element %p name %s", element, element->name);
865
866         for (i = 0; propid_table[i].name; i++) {
867                 DBG("property %s", propid_table[i].name);
868
869                 property = create_property(element, propid_table[i].id);
870
871                 property->flags &= ~CONNMAN_PROPERTY_FLAG_REFERENCE;
872
873                 if (propid_table[i].type != DBUS_TYPE_STRING)
874                         continue;
875
876                 if (propid_table[i].value)
877                         property->value = g_strdup(propid_table[i].value);
878                 else
879                         property->value = g_strdup("");
880         }
881 }
882
883 static int define_properties_valist(struct connman_element *element,
884                                                                 va_list args)
885 {
886         enum connman_property_id id;
887
888         DBG("element %p name %s", element, element->name);
889
890         id = va_arg(args, enum connman_property_id);
891
892         while (id != CONNMAN_PROPERTY_ID_INVALID) {
893
894                 DBG("property %d", id);
895
896                 create_property(element, id);
897
898                 id = va_arg(args, enum connman_property_id);
899         }
900
901         return 0;
902 }
903
904 /**
905  * connman_element_define_properties:
906  * @element: an element
907  * @varargs: list of property identifiers
908  *
909  * Define the valid properties for an element.
910  *
911  * Returns: %0 on success
912  */
913 int connman_element_define_properties(struct connman_element *element, ...)
914 {
915         va_list args;
916         int err;
917
918         DBG("element %p name %s", element, element->name);
919
920         va_start(args, element);
921
922         err = define_properties_valist(element, args);
923
924         va_end(args);
925
926         return err;
927 }
928
929 int connman_element_create_property(struct connman_element *element,
930                                                 const char *name, int type)
931 {
932         return -EIO;
933 }
934
935 int connman_element_set_property(struct connman_element *element,
936                                 enum connman_property_id id, const void *value)
937 {
938         switch (id) {
939         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
940                 __connman_element_lock(element);
941                 g_free(element->ipv4.address);
942                 element->ipv4.address = g_strdup(*((const char **) value));
943                 __connman_element_unlock(element);
944                 break;
945         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
946                 __connman_element_lock(element);
947                 g_free(element->ipv4.netmask);
948                 element->ipv4.netmask = g_strdup(*((const char **) value));
949                 __connman_element_unlock(element);
950                 break;
951         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
952                 __connman_element_lock(element);
953                 g_free(element->ipv4.gateway);
954                 element->ipv4.gateway = g_strdup(*((const char **) value));
955                 __connman_element_unlock(element);
956                 break;
957         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
958                 __connman_element_lock(element);
959                 g_free(element->ipv4.broadcast);
960                 element->ipv4.broadcast = g_strdup(*((const char **) value));
961                 __connman_element_unlock(element);
962                 break;
963         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
964                 __connman_element_lock(element);
965                 g_free(element->ipv4.nameserver);
966                 element->ipv4.nameserver = g_strdup(*((const char **) value));
967                 __connman_element_unlock(element);
968                 break;
969         default:
970                 return -EINVAL;
971         }
972
973         return 0;
974 }
975
976 int connman_element_get_value(struct connman_element *element,
977                                 enum connman_property_id id, void *value)
978 {
979         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
980                 return -EINVAL;
981
982         switch (id) {
983         case CONNMAN_PROPERTY_ID_IPV4_METHOD:
984                 if (element->ipv4.method == CONNMAN_IPV4_METHOD_UNKNOWN)
985                         return connman_element_get_value(element->parent,
986                                                                 id, value);
987                 __connman_element_lock(element);
988                 *((const char **) value) = __connman_ipv4_method2string(element->ipv4.method);
989                 __connman_element_unlock(element);
990                 break;
991         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
992                 if (element->ipv4.address == NULL)
993                         return connman_element_get_value(element->parent,
994                                                                 id, value);
995                 __connman_element_lock(element);
996                 *((char **) value) = element->ipv4.address;
997                 __connman_element_unlock(element);
998                 break;
999         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
1000                 if (element->ipv4.netmask == NULL)
1001                         return connman_element_get_value(element->parent,
1002                                                                 id, value);
1003                 __connman_element_lock(element);
1004                 *((char **) value) = element->ipv4.netmask;
1005                 __connman_element_unlock(element);
1006                 break;
1007         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
1008                 if (element->ipv4.gateway == NULL)
1009                         return connman_element_get_value(element->parent,
1010                                                                 id, value);
1011                 __connman_element_lock(element);
1012                 *((char **) value) = element->ipv4.gateway;
1013                 __connman_element_unlock(element);
1014                 break;
1015         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
1016                 if (element->ipv4.broadcast == NULL)
1017                         return connman_element_get_value(element->parent,
1018                                                                 id, value);
1019                 __connman_element_lock(element);
1020                 *((char **) value) = element->ipv4.broadcast;
1021                 __connman_element_unlock(element);
1022                 break;
1023         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
1024                 if (element->ipv4.nameserver == NULL)
1025                         return connman_element_get_value(element->parent,
1026                                                                 id, value);
1027                 __connman_element_lock(element);
1028                 *((char **) value) = element->ipv4.nameserver;
1029                 __connman_element_unlock(element);
1030                 break;
1031         default:
1032                 return -EINVAL;
1033         }
1034
1035         return 0;
1036 }
1037
1038 gboolean connman_element_get_static_property(struct connman_element *element,
1039                                                 const char *name, void *value)
1040 {
1041         GSList *list;
1042         gboolean found = FALSE;
1043
1044         DBG("element %p name %s", element, element->name);
1045
1046         __connman_element_lock(element);
1047
1048         for (list = element->properties; list; list = list->next) {
1049                 struct connman_property *property = list->data;
1050
1051                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1052                         continue;
1053
1054                 if (g_str_equal(property->name, name) == TRUE) {
1055                         switch (property->type) {
1056                         case DBUS_TYPE_STRING:
1057                                 *((char **) value) = property->value;
1058                                 found = TRUE;
1059                                 break;
1060                         case DBUS_TYPE_BYTE:
1061                                 memcpy(value, property->value, 1);
1062                                 found = TRUE;
1063                                 break;
1064                         }
1065                         break;
1066                 }
1067         }
1068
1069         __connman_element_unlock(element);
1070
1071         if (found == FALSE && element->parent != NULL)
1072                 return connman_element_get_static_property(element->parent,
1073                                                                 name, value);
1074
1075         return found;
1076 }
1077
1078 gboolean connman_element_get_static_array_property(struct connman_element *element,
1079                                         const char *name, void *value, int *len)
1080 {
1081         GSList *list;
1082         gboolean found = FALSE;
1083
1084         DBG("element %p name %s", element, element->name);
1085
1086         __connman_element_lock(element);
1087
1088         for (list = element->properties; list; list = list->next) {
1089                 struct connman_property *property = list->data;
1090
1091                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1092                         continue;
1093
1094                 if (g_str_equal(property->name, name) == TRUE) {
1095                         *((char **) value) = property->value;
1096                         *len = property->size;
1097                         found = TRUE;
1098                         break;
1099                 }
1100         }
1101
1102         __connman_element_unlock(element);
1103
1104         return found;
1105 }
1106
1107 gboolean connman_element_match_static_property(struct connman_element *element,
1108                                         const char *name, const void *value)
1109 {
1110         GSList *list;
1111         gboolean result = FALSE;
1112
1113         DBG("element %p name %s", element, element->name);
1114
1115         __connman_element_lock(element);
1116
1117         for (list = element->properties; list; list = list->next) {
1118                 struct connman_property *property = list->data;
1119
1120                 if (!(property->flags & CONNMAN_PROPERTY_FLAG_STATIC))
1121                         continue;
1122
1123                 if (g_str_equal(property->name, name) == FALSE)
1124                         continue;
1125
1126                 if (property->type == DBUS_TYPE_STRING)
1127                         result = g_str_equal(property->value,
1128                                                 *((const char **) value));
1129
1130                 if (result == TRUE)
1131                         break;
1132         }
1133
1134         __connman_element_unlock(element);
1135
1136         return result;
1137 }
1138
1139 static void append_connections(DBusMessageIter *entry)
1140 {
1141         DBusMessageIter value, iter;
1142         const char *key = "Connections";
1143
1144         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1145
1146         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1147                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
1148                                                                 &value);
1149
1150         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
1151                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
1152         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
1153         dbus_message_iter_close_container(&value, &iter);
1154
1155         dbus_message_iter_close_container(entry, &value);
1156 }
1157
1158 static void emit_connections_signal(DBusConnection *conn)
1159 {
1160         DBusMessage *signal;
1161         DBusMessageIter entry;
1162
1163         DBG("conn %p", conn);
1164
1165         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1166                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1167         if (signal == NULL)
1168                 return;
1169
1170         dbus_message_iter_init_append(signal, &entry);
1171
1172         append_connections(&entry);
1173
1174         g_dbus_send_message(conn, signal);
1175 }
1176
1177 static void append_state(DBusMessageIter *entry, const char *state)
1178 {
1179         DBusMessageIter value;
1180         const char *key = "State";
1181
1182         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1183
1184         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1185                                         DBUS_TYPE_STRING_AS_STRING, &value);
1186         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1187         dbus_message_iter_close_container(entry, &value);
1188 }
1189
1190 static void emit_state_change(DBusConnection *conn, const char *state)
1191 {
1192         DBusMessage *signal;
1193         DBusMessageIter entry;
1194
1195         DBG("conn %p", conn);
1196
1197         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1198                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1199         if (signal == NULL)
1200                 return;
1201
1202         dbus_message_iter_init_append(signal, &entry);
1203
1204         append_state(&entry, state);
1205
1206         g_dbus_send_message(conn, signal);
1207 }
1208
1209 static void probe_element(struct connman_element *element)
1210 {
1211         GSList *list;
1212
1213         DBG("element %p name %s", element, element->name);
1214
1215         for (list = driver_list; list; list = list->next) {
1216                 struct connman_driver *driver = list->data;
1217
1218                 if (match_driver(element, driver) == FALSE)
1219                         continue;
1220
1221                 DBG("driver %p name %s", driver, driver->name);
1222
1223                 if (driver->probe(element) == 0) {
1224                         __connman_element_lock(element);
1225                         element->driver = driver;
1226                         __connman_element_unlock(element);
1227                         break;
1228                 }
1229         }
1230 }
1231
1232 static void register_element(gpointer data, gpointer user_data)
1233 {
1234         struct connman_element *element = data;
1235         const gchar *basepath;
1236         GNode *node;
1237
1238         __connman_element_lock(element);
1239
1240         if (element->parent) {
1241                 node = g_node_find(element_root, G_PRE_ORDER,
1242                                         G_TRAVERSE_ALL, element->parent);
1243                 basepath = element->parent->path;
1244         } else {
1245                 element->parent = element_root->data;
1246
1247                 node = element_root;
1248                 basepath = "";
1249         }
1250
1251         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1252
1253         set_reference_properties(element);
1254
1255         __connman_element_unlock(element);
1256
1257         DBG("element %p path %s", element, element->path);
1258
1259         g_node_append_data(node, element);
1260
1261         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1262                 emit_connections_signal(connection);
1263                 emit_state_change(connection, "online");
1264         }
1265
1266         emit_element_signal(connection, "ElementAdded", element);
1267
1268         if (started == FALSE)
1269                 return;
1270
1271         probe_element(element);
1272 }
1273
1274 /**
1275  * connman_element_register:
1276  * @element: the element to register
1277  * @parent: the parent to register the element with
1278  *
1279  * Register an element with the core. It will be register under the given
1280  * parent of if %NULL is provided under the root element.
1281  *
1282  * Returns: %0 on success
1283  */
1284 int connman_element_register(struct connman_element *element,
1285                                         struct connman_element *parent)
1286 {
1287         DBG("element %p name %s parent %p", element, element->name, parent);
1288
1289         if (element->devname == NULL)
1290                 element->devname = g_strdup(element->name);
1291
1292         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1293                 if (g_pattern_match_simple(device_filter,
1294                                                 element->devname) == FALSE) {
1295                         DBG("ignoring %s [%s] device", element->name,
1296                                                         element->devname);
1297                         return -EPERM;
1298                 }
1299         }
1300
1301         if (connman_element_ref(element) == NULL)
1302                 return -EINVAL;
1303
1304         __connman_element_lock(element);
1305
1306         if (element->name == NULL) {
1307                 element->name = g_strdup(type2string(element->type));
1308                 if (element->name == NULL) {
1309                         __connman_element_unlock(element);
1310                         return -EINVAL;
1311                 }
1312         }
1313
1314         if (element->type == CONNMAN_ELEMENT_TYPE_DHCP)
1315                 element->ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
1316
1317         element->parent = parent;
1318
1319         __connman_element_unlock(element);
1320
1321         register_element(element, NULL);
1322
1323         return 0;
1324 }
1325
1326 static gboolean remove_element(GNode *node, gpointer user_data)
1327 {
1328         struct connman_element *element = node->data;
1329         struct connman_element *root = user_data;
1330
1331         DBG("element %p name %s", element, element->name);
1332
1333         if (element == root)
1334                 return FALSE;
1335
1336         if (node != NULL)
1337                 g_node_unlink(node);
1338
1339         if (element->driver) {
1340                 if (element->driver->remove)
1341                         element->driver->remove(element);
1342
1343                 __connman_element_lock(element);
1344                 element->driver = NULL;
1345                 __connman_element_unlock(element);
1346         }
1347
1348         if (node != NULL)
1349                 g_node_destroy(node);
1350
1351         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1352                 if (__connman_element_count(NULL,
1353                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1354                         emit_state_change(connection, "offline");
1355                 emit_connections_signal(connection);
1356         }
1357
1358         emit_element_signal(connection, "ElementRemoved", element);
1359
1360         connman_element_unref(element);
1361
1362         return FALSE;
1363 }
1364
1365 void connman_element_unregister(struct connman_element *element)
1366 {
1367         GNode *node;
1368
1369         DBG("element %p name %s", element, element->name);
1370
1371         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1372
1373         if (node != NULL)
1374                 g_node_traverse(node, G_POST_ORDER,
1375                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1376 }
1377
1378 void connman_element_unregister_children(struct connman_element *element)
1379 {
1380         GNode *node;
1381
1382         DBG("element %p name %s", element, element->name);
1383
1384         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1385
1386         if (node != NULL)
1387                 g_node_traverse(node, G_POST_ORDER,
1388                                 G_TRAVERSE_ALL, -1, remove_element, element);
1389 }
1390
1391 static gboolean update_element(GNode *node, gpointer user_data)
1392 {
1393         struct connman_element *element = node->data;
1394
1395         DBG("element %p name %s", element, element->name);
1396
1397         if (element->driver && element->driver->update)
1398                 element->driver->update(element);
1399
1400         emit_element_signal(connection, "ElementUpdated", element);
1401
1402         return FALSE;
1403 }
1404
1405 void connman_element_update(struct connman_element *element)
1406 {
1407         GNode *node;
1408
1409         DBG("element %p name %s", element, element->name);
1410
1411         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1412
1413         if (node != NULL)
1414                 g_node_traverse(node, G_PRE_ORDER,
1415                                 G_TRAVERSE_ALL, -1, update_element, element);
1416 }
1417
1418 int connman_element_set_enabled(struct connman_element *element,
1419                                                         gboolean enabled)
1420 {
1421         if (element->enabled == enabled)
1422                 return 0;
1423
1424         element->enabled = enabled;
1425
1426         return 0;
1427 }
1428
1429 int __connman_element_init(DBusConnection *conn, const char *device)
1430 {
1431         struct connman_element *element;
1432
1433         DBG("conn %p", conn);
1434
1435         connection = dbus_connection_ref(conn);
1436         if (connection == NULL)
1437                 return -EIO;
1438
1439         device_filter = g_strdup(device);
1440
1441         element = connman_element_create("root");
1442
1443         element->path = g_strdup("/");
1444         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1445
1446         create_default_properties(element);
1447
1448         element_root = g_node_new(element);
1449
1450         __connman_network_init();
1451         __connman_device_init();
1452
1453         return 0;
1454 }
1455
1456 static gboolean probe_node(GNode *node, gpointer data)
1457 {
1458         struct connman_element *element = node->data;
1459
1460         DBG("element %p name %s", element, element->name);
1461
1462         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1463                 return FALSE;
1464
1465         if (element->driver)
1466                 return FALSE;
1467
1468         probe_element(element);
1469
1470         return FALSE;
1471 }
1472
1473 void __connman_element_start(void)
1474 {
1475         DBG("");
1476
1477         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1478                                                         probe_node, NULL);
1479
1480         started = TRUE;
1481
1482         __connman_storage_init_device();
1483
1484         __connman_connection_init();
1485         __connman_ipv4_init();
1486         __connman_detect_init();
1487 }
1488
1489 void __connman_element_stop(void)
1490 {
1491         DBG("");
1492
1493         __connman_detect_cleanup();
1494         __connman_ipv4_cleanup();
1495         __connman_connection_cleanup();
1496 }
1497
1498 static gboolean free_driver(GNode *node, gpointer data)
1499 {
1500         struct connman_element *element = node->data;
1501
1502         DBG("element %p name %s", element, element->name);
1503
1504         if (element->driver) {
1505                 if (element->driver->remove)
1506                         element->driver->remove(element);
1507
1508                 __connman_element_lock(element);
1509                 element->driver = NULL;
1510                 __connman_element_unlock(element);
1511         }
1512
1513         return FALSE;
1514 }
1515
1516 static gboolean free_node(GNode *node, gpointer data)
1517 {
1518         struct connman_element *element = node->data;
1519
1520         DBG("element %p name %s", element, element->name);
1521
1522         if (g_node_depth(node) > 1)
1523                 connman_element_unregister(element);
1524
1525         return FALSE;
1526 }
1527
1528 void __connman_element_cleanup(void)
1529 {
1530         DBG("");
1531
1532         __connman_device_cleanup();
1533         __connman_network_cleanup();
1534
1535         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1536                                                         free_driver, NULL);
1537
1538         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1539                                                         free_node, NULL);
1540
1541         g_node_destroy(element_root);
1542         element_root = NULL;
1543
1544         g_free(device_filter);
1545
1546         dbus_connection_unref(connection);
1547 }