Add support for static IPv4 settings
[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 const char *type2string(enum connman_element_type type)
44 {
45         switch (type) {
46         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
47                 return "unknown";
48         case CONNMAN_ELEMENT_TYPE_ROOT:
49                 return "root";
50         case CONNMAN_ELEMENT_TYPE_PROFILE:
51                 return "profile";
52         case CONNMAN_ELEMENT_TYPE_DEVICE:
53                 return "device";
54         case CONNMAN_ELEMENT_TYPE_NETWORK:
55                 return "network";
56         case CONNMAN_ELEMENT_TYPE_SERVICE:
57                 return "service";
58         case CONNMAN_ELEMENT_TYPE_PPP:
59                 return "ppp";
60         case CONNMAN_ELEMENT_TYPE_IPV4:
61                 return "ipv4";
62         case CONNMAN_ELEMENT_TYPE_IPV6:
63                 return "ipv6";
64         case CONNMAN_ELEMENT_TYPE_DHCP:
65                 return "dhcp";
66         case CONNMAN_ELEMENT_TYPE_BOOTP:
67                 return "bootp";
68         case CONNMAN_ELEMENT_TYPE_ZEROCONF:
69                 return "zeroconf";
70         case CONNMAN_ELEMENT_TYPE_CONNECTION:
71                 return "connection";
72         case CONNMAN_ELEMENT_TYPE_VENDOR:
73                 return "vendor";
74         }
75
76         return NULL;
77 }
78
79 const char *__connman_ipv4_method2string(enum connman_ipv4_method method)
80 {
81         switch (method) {
82         case CONNMAN_IPV4_METHOD_UNKNOWN:
83                 return "unknown";
84         case CONNMAN_IPV4_METHOD_OFF:
85                 return "off";
86         case CONNMAN_IPV4_METHOD_STATIC:
87                 return "static";
88         case CONNMAN_IPV4_METHOD_DHCP:
89                 return "dhcp";
90         }
91
92         return "unknown";
93 }
94
95 enum connman_ipv4_method __connman_ipv4_string2method(const char *method)
96 {
97         if (strcasecmp(method, "off") == 0)
98                 return CONNMAN_IPV4_METHOD_OFF;
99         else if (strcasecmp(method, "static") == 0)
100                 return CONNMAN_IPV4_METHOD_STATIC;
101         else if (strcasecmp(method, "dhcp") == 0)
102                 return CONNMAN_IPV4_METHOD_DHCP;
103         else
104                 return CONNMAN_IPV4_METHOD_UNKNOWN;
105 }
106
107 static void emit_element_signal(DBusConnection *conn, const char *member,
108                                         struct connman_element *element)
109 {
110         DBusMessage *signal;
111
112         if (__connman_debug_enabled() == FALSE)
113                 return;
114
115         DBG("conn %p member %s", conn, member);
116
117         if (element == NULL)
118                 return;
119
120         signal = dbus_message_new_signal(element->path,
121                                         CONNMAN_DEBUG_INTERFACE, member);
122         if (signal == NULL)
123                 return;
124
125         g_dbus_send_message(conn, signal);
126 }
127
128 struct foreach_data {
129         enum connman_element_type type;
130         element_cb_t callback;
131         gpointer user_data;
132 };
133
134 static gboolean foreach_callback(GNode *node, gpointer user_data)
135 {
136         struct connman_element *element = node->data;
137         struct foreach_data *data = user_data;
138
139         DBG("element %p name %s", element, element->name);
140
141         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
142                 return FALSE;
143
144         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
145                                         data->type != element->type)
146                 return FALSE;
147
148         if (data->callback)
149                 data->callback(element, data->user_data);
150
151         return FALSE;
152 }
153
154 void __connman_element_foreach(struct connman_element *element,
155                                 enum connman_element_type type,
156                                 element_cb_t callback, gpointer user_data)
157 {
158         struct foreach_data data = { type, callback, user_data };
159         GNode *node;
160
161         DBG("");
162
163         if (element != NULL) {
164                 node = g_node_find(element_root, G_PRE_ORDER,
165                                                 G_TRAVERSE_ALL, element);
166                 if (node == NULL)
167                         return;
168         } else
169                 node = element_root;
170
171         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
172                                                 foreach_callback, &data);
173 }
174
175 struct append_filter {
176         enum connman_element_type type;
177         DBusMessageIter *iter;
178 };
179
180 static gboolean append_path(GNode *node, gpointer user_data)
181 {
182         struct connman_element *element = node->data;
183         struct append_filter *filter = user_data;
184
185         DBG("element %p name %s", element, element->name);
186
187         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
188                 return FALSE;
189
190         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
191                                         filter->type != element->type)
192                 return FALSE;
193
194         if (filter->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
195                         __connman_device_has_driver(element->device) == FALSE)
196                 return FALSE;
197
198         if (filter->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
199                         __connman_network_has_driver(element->network) == FALSE)
200                 return FALSE;
201
202         dbus_message_iter_append_basic(filter->iter,
203                                 DBUS_TYPE_OBJECT_PATH, &element->path);
204
205         return FALSE;
206 }
207
208 void __connman_element_list(struct connman_element *element,
209                                         enum connman_element_type type,
210                                                         DBusMessageIter *iter)
211 {
212         struct append_filter filter = { type, iter };
213         GNode *node;
214
215         DBG("");
216
217         if (element != NULL) {
218                 node = g_node_find(element_root, G_PRE_ORDER,
219                                                 G_TRAVERSE_ALL, element);
220                 if (node == NULL)
221                         return;
222         } else
223                 node = element_root;
224
225         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
226                                                 append_path, &filter);
227 }
228
229 struct count_data {
230         enum connman_element_type type;
231         int count;
232 };
233
234 static gboolean count_element(GNode *node, gpointer user_data)
235 {
236         struct connman_element *element = node->data;
237         struct count_data *data = user_data;
238
239         DBG("element %p name %s", element, element->name);
240
241         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
242                 return FALSE;
243
244         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
245                                         data->type != element->type)
246                 return FALSE;
247
248         data->count++;
249
250         return FALSE;
251 }
252
253 int __connman_element_count(struct connman_element *element,
254                                         enum connman_element_type type)
255 {
256         struct count_data data = { type, 0 };
257         GNode *node;
258
259         DBG("");
260
261         if (element != NULL) {
262                 node = g_node_find(element_root, G_PRE_ORDER,
263                                                 G_TRAVERSE_ALL, element);
264                 if (node == NULL)
265                         return 0;
266         } else
267                 node = element_root;
268
269         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
270                                                 count_element, &data);
271
272         return data.count;
273 }
274
275 const char *__connman_element_get_device(struct connman_element *element)
276 {
277         if (element->type == CONNMAN_ELEMENT_TYPE_DEVICE &&
278                                                 element->device != NULL)
279                 return element->path;
280
281         if (element->parent == NULL)
282                 return NULL;
283
284         return __connman_element_get_device(element->parent);
285 }
286
287 const char *__connman_element_get_network(struct connman_element *element)
288 {
289         if (element->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
290                                                 element->network != NULL)
291                 return element->path;
292
293         if (element->parent == NULL)
294                 return NULL;
295
296         return __connman_element_get_network(element->parent);
297 }
298
299 static gint compare_priority(gconstpointer a, gconstpointer b)
300 {
301         const struct connman_driver *driver1 = a;
302         const struct connman_driver *driver2 = b;
303
304         return driver2->priority - driver1->priority;
305 }
306
307 static gboolean match_driver(struct connman_element *element,
308                                         struct connman_driver *driver)
309 {
310         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
311                 return FALSE;
312
313         if (element->type == driver->type ||
314                         driver->type == CONNMAN_ELEMENT_TYPE_UNKNOWN)
315                 return TRUE;
316
317         return FALSE;
318 }
319
320 static gboolean probe_driver(GNode *node, gpointer data)
321 {
322         struct connman_element *element = node->data;
323         struct connman_driver *driver = data;
324
325         DBG("element %p name %s", element, element->name);
326
327         if (!element->driver && match_driver(element, driver) == TRUE) {
328                 if (driver->probe(element) < 0)
329                         return FALSE;
330
331                 __connman_element_lock(element);
332                 element->driver = driver;
333                 __connman_element_unlock(element);
334         }
335
336         return FALSE;
337 }
338
339 void __connman_driver_rescan(struct connman_driver *driver)
340 {
341         DBG("driver %p name %s", driver, driver->name);
342
343         if (!driver->probe)
344                 return;
345
346         if (element_root != NULL)
347                 g_node_traverse(element_root, G_PRE_ORDER,
348                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
349 }
350
351 /**
352  * connman_driver_register:
353  * @driver: driver definition
354  *
355  * Register a new driver
356  *
357  * Returns: %0 on success
358  */
359 int connman_driver_register(struct connman_driver *driver)
360 {
361         DBG("driver %p name %s", driver, driver->name);
362
363         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
364                 return -EINVAL;
365
366         if (!driver->probe)
367                 return -EINVAL;
368
369         driver_list = g_slist_insert_sorted(driver_list, driver,
370                                                         compare_priority);
371
372         if (started == FALSE)
373                 return 0;
374
375         if (element_root != NULL)
376                 g_node_traverse(element_root, G_PRE_ORDER,
377                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
378
379         return 0;
380 }
381
382 static gboolean remove_driver(GNode *node, gpointer data)
383 {
384         struct connman_element *element = node->data;
385         struct connman_driver *driver = data;
386
387         DBG("element %p name %s", element, element->name);
388
389         if (element->driver == driver) {
390                 if (driver->remove)
391                         driver->remove(element);
392
393                 __connman_element_lock(element);
394                 element->driver = NULL;
395                 __connman_element_unlock(element);
396         }
397
398         return FALSE;
399 }
400
401 /**
402  * connman_driver_unregister:
403  * @driver: driver definition
404  *
405  * Remove a previously registered driver
406  */
407 void connman_driver_unregister(struct connman_driver *driver)
408 {
409         DBG("driver %p name %s", driver, driver->name);
410
411         driver_list = g_slist_remove(driver_list, driver);
412
413         if (element_root != NULL)
414                 g_node_traverse(element_root, G_POST_ORDER,
415                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
416 }
417
418 static void unregister_property(gpointer data)
419 {
420         struct connman_property *property = data;
421
422         DBG("property %p", property);
423
424         if (!(property->flags & CONNMAN_PROPERTY_FLAG_REFERENCE))
425                 g_free(property->value);
426
427         g_free(property->name);
428         g_free(property);
429 }
430
431 void __connman_element_initialize(struct connman_element *element)
432 {
433         DBG("element %p", element);
434
435         element->refcount = 1;
436
437         element->name    = NULL;
438         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
439         element->index   = -1;
440         element->enabled = FALSE;
441
442         element->properties = g_hash_table_new_full(g_str_hash, g_direct_equal,
443                                                 g_free, unregister_property);
444 }
445
446 /**
447  * connman_element_create:
448  * @name: element name
449  *
450  * Allocate a new element and assign the given #name to it. If the name
451  * is #NULL, it will be later on created based on the element type.
452  *
453  * Returns: a newly-allocated #connman_element structure
454  */
455 struct connman_element *connman_element_create(const char *name)
456 {
457         struct connman_element *element;
458
459         element = g_try_new0(struct connman_element, 1);
460         if (element == NULL)
461                 return NULL;
462
463         DBG("element %p", element);
464
465         __connman_element_initialize(element);
466
467         return element;
468 }
469
470 struct connman_element *connman_element_ref(struct connman_element *element)
471 {
472         DBG("element %p name %s refcount %d", element, element->name,
473                                 g_atomic_int_get(&element->refcount) + 1);
474
475         g_atomic_int_inc(&element->refcount);
476
477         return element;
478 }
479
480 static void free_properties(struct connman_element *element)
481 {
482         DBG("element %p name %s", element, element->name);
483
484         __connman_element_lock(element);
485
486         g_hash_table_destroy(element->properties);
487         element->properties = NULL;
488
489         __connman_element_unlock(element);
490 }
491
492 void connman_element_unref(struct connman_element *element)
493 {
494         DBG("element %p name %s refcount %d", element, element->name,
495                                 g_atomic_int_get(&element->refcount) - 1);
496
497         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
498                 if (element->destruct)
499                         element->destruct(element);
500                 free_properties(element);
501                 g_free(element->ipv4.address);
502                 g_free(element->ipv4.netmask);
503                 g_free(element->ipv4.gateway);
504                 g_free(element->ipv4.network);
505                 g_free(element->ipv4.broadcast);
506                 g_free(element->ipv4.nameserver);
507                 g_free(element->devname);
508                 g_free(element->path);
509                 g_free(element->name);
510                 g_free(element);
511         }
512 }
513
514 int connman_element_add_static_property(struct connman_element *element,
515                                 const char *name, int type, const void *value)
516 {
517         struct connman_property *property;
518
519         DBG("element %p name %s", element, element->name);
520
521         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
522                 return -EINVAL;
523
524         property = g_try_new0(struct connman_property, 1);
525         if (property == NULL)
526                 return -ENOMEM;
527
528         property->flags = CONNMAN_PROPERTY_FLAG_STATIC;
529         property->id    = CONNMAN_PROPERTY_ID_INVALID;
530         property->name  = g_strdup(name);
531         property->type  = type;
532
533         DBG("name %s type %d value %p", name, type, value);
534
535         switch (type) {
536         case DBUS_TYPE_STRING:
537                 property->value = g_strdup(*((const char **) value));
538                 break;
539         case DBUS_TYPE_BYTE:
540                 property->value = g_try_malloc(1);
541                 if (property->value != NULL)
542                         memcpy(property->value, value, 1);
543                 break;
544         }
545
546         __connman_element_lock(element);
547
548         g_hash_table_insert(element->properties, g_strdup(name), property);
549
550         __connman_element_unlock(element);
551
552         return 0;
553 }
554
555 int connman_element_set_static_property(struct connman_element *element,
556                                 const char *name, int type, const void *value)
557 {
558         struct connman_property *property;
559
560         DBG("element %p name %s", element, element->name);
561
562         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
563                 return -EINVAL;
564
565         __connman_element_lock(element);
566
567         property = g_hash_table_lookup(element->properties, name);
568         if (property != NULL) {
569                 property->flags |= CONNMAN_PROPERTY_FLAG_STATIC;
570
571                 property->type = type;
572                 g_free(property->value);
573
574                 switch (type) {
575                 case DBUS_TYPE_STRING:
576                         property->value = g_strdup(*((const char **) value));
577                         break;
578                 case DBUS_TYPE_BYTE:
579                         property->value = g_try_malloc(1);
580                         if (property->value != NULL)
581                                 memcpy(property->value, value, 1);
582                         break;
583                 }
584         }
585
586         __connman_element_unlock(element);
587
588         return 0;
589 }
590
591 int connman_element_add_static_array_property(struct connman_element *element,
592                         const char *name, int type, const void *value, int len)
593 {
594         struct connman_property *property;
595
596         DBG("element %p name %s", element, element->name);
597
598         if (type != DBUS_TYPE_BYTE)
599                 return -EINVAL;
600
601         property = g_try_new0(struct connman_property, 1);
602         if (property == NULL)
603                 return -ENOMEM;
604
605         property->flags   = CONNMAN_PROPERTY_FLAG_STATIC;
606         property->id      = CONNMAN_PROPERTY_ID_INVALID;
607         property->name    = g_strdup(name);
608         property->type    = DBUS_TYPE_ARRAY;
609         property->subtype = type;
610
611         DBG("name %s type %d value %p", name, type, value);
612
613         switch (type) {
614         case DBUS_TYPE_BYTE:
615                 property->value = g_try_malloc(len);
616                 if (property->value != NULL) {
617                         memcpy(property->value,
618                                 *((const unsigned char **) value), len);
619                         property->size = len;
620                 }
621                 break;
622         }
623
624         __connman_element_lock(element);
625
626         g_hash_table_insert(element->properties, g_strdup(name), property);
627
628         __connman_element_unlock(element);
629
630         return 0;
631 }
632
633 int connman_element_set_property(struct connman_element *element,
634                                 enum connman_property_id id, const void *value)
635 {
636         switch (id) {
637         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
638                 __connman_element_lock(element);
639                 g_free(element->ipv4.address);
640                 element->ipv4.address = g_strdup(*((const char **) value));
641                 __connman_element_unlock(element);
642                 break;
643         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
644                 __connman_element_lock(element);
645                 g_free(element->ipv4.netmask);
646                 element->ipv4.netmask = g_strdup(*((const char **) value));
647                 __connman_element_unlock(element);
648                 break;
649         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
650                 __connman_element_lock(element);
651                 g_free(element->ipv4.gateway);
652                 element->ipv4.gateway = g_strdup(*((const char **) value));
653                 __connman_element_unlock(element);
654                 break;
655         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
656                 __connman_element_lock(element);
657                 g_free(element->ipv4.broadcast);
658                 element->ipv4.broadcast = g_strdup(*((const char **) value));
659                 __connman_element_unlock(element);
660                 break;
661         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
662                 __connman_element_lock(element);
663                 g_free(element->ipv4.nameserver);
664                 element->ipv4.nameserver = g_strdup(*((const char **) value));
665                 __connman_element_unlock(element);
666                 break;
667         default:
668                 return -EINVAL;
669         }
670
671         return 0;
672 }
673
674 int connman_element_get_value(struct connman_element *element,
675                                 enum connman_property_id id, void *value)
676 {
677         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
678                 return -EINVAL;
679
680         switch (id) {
681         case CONNMAN_PROPERTY_ID_IPV4_METHOD:
682                 if (element->ipv4.method == CONNMAN_IPV4_METHOD_UNKNOWN)
683                         return connman_element_get_value(element->parent,
684                                                                 id, value);
685                 __connman_element_lock(element);
686                 *((const char **) value) = __connman_ipv4_method2string(element->ipv4.method);
687                 __connman_element_unlock(element);
688                 break;
689         case CONNMAN_PROPERTY_ID_IPV4_ADDRESS:
690                 if (element->ipv4.address == NULL)
691                         return connman_element_get_value(element->parent,
692                                                                 id, value);
693                 __connman_element_lock(element);
694                 *((char **) value) = element->ipv4.address;
695                 __connman_element_unlock(element);
696                 break;
697         case CONNMAN_PROPERTY_ID_IPV4_NETMASK:
698                 if (element->ipv4.netmask == NULL)
699                         return connman_element_get_value(element->parent,
700                                                                 id, value);
701                 __connman_element_lock(element);
702                 *((char **) value) = element->ipv4.netmask;
703                 __connman_element_unlock(element);
704                 break;
705         case CONNMAN_PROPERTY_ID_IPV4_GATEWAY:
706                 if (element->ipv4.gateway == NULL)
707                         return connman_element_get_value(element->parent,
708                                                                 id, value);
709                 __connman_element_lock(element);
710                 *((char **) value) = element->ipv4.gateway;
711                 __connman_element_unlock(element);
712                 break;
713         case CONNMAN_PROPERTY_ID_IPV4_BROADCAST:
714                 if (element->ipv4.broadcast == NULL)
715                         return connman_element_get_value(element->parent,
716                                                                 id, value);
717                 __connman_element_lock(element);
718                 *((char **) value) = element->ipv4.broadcast;
719                 __connman_element_unlock(element);
720                 break;
721         case CONNMAN_PROPERTY_ID_IPV4_NAMESERVER:
722                 if (element->ipv4.nameserver == NULL)
723                         return connman_element_get_value(element->parent,
724                                                                 id, value);
725                 __connman_element_lock(element);
726                 *((char **) value) = element->ipv4.nameserver;
727                 __connman_element_unlock(element);
728                 break;
729         default:
730                 return -EINVAL;
731         }
732
733         return 0;
734 }
735
736 gboolean connman_element_get_static_property(struct connman_element *element,
737                                                 const char *name, void *value)
738 {
739         struct connman_property *property;
740         gboolean found = FALSE;
741
742         DBG("element %p name %s", element, element->name);
743
744         __connman_element_lock(element);
745
746         property = g_hash_table_lookup(element->properties, name);
747         if (property != NULL &&
748                         (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) {
749                 if (g_str_equal(property->name, name) == TRUE) {
750                         switch (property->type) {
751                         case DBUS_TYPE_STRING:
752                                 *((char **) value) = property->value;
753                                 found = TRUE;
754                                 break;
755                         case DBUS_TYPE_BYTE:
756                                 memcpy(value, property->value, 1);
757                                 found = TRUE;
758                                 break;
759                         }
760                 }
761         }
762
763         __connman_element_unlock(element);
764
765         if (found == FALSE && element->parent != NULL)
766                 return connman_element_get_static_property(element->parent,
767                                                                 name, value);
768
769         return found;
770 }
771
772 gboolean connman_element_get_static_array_property(struct connman_element *element,
773                                         const char *name, void *value, int *len)
774 {
775         struct connman_property *property;
776         gboolean found = FALSE;
777
778         DBG("element %p name %s", element, element->name);
779
780         __connman_element_lock(element);
781
782         property = g_hash_table_lookup(element->properties, name);
783         if (property != NULL &&
784                         (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) {
785                 if (g_str_equal(property->name, name) == TRUE) {
786                         *((char **) value) = property->value;
787                         *len = property->size;
788                         found = TRUE;
789                 }
790         }
791
792         __connman_element_unlock(element);
793
794         return found;
795 }
796
797 gboolean connman_element_match_static_property(struct connman_element *element,
798                                         const char *name, const void *value)
799 {
800         struct connman_property *property;
801         gboolean result = FALSE;
802
803         DBG("element %p name %s", element, element->name);
804
805         __connman_element_lock(element);
806
807         property = g_hash_table_lookup(element->properties, name);
808         if (property != NULL &&
809                         (property->flags & CONNMAN_PROPERTY_FLAG_STATIC)) {
810                 if (g_str_equal(property->name, name) == TRUE &&
811                                         property->type == DBUS_TYPE_STRING)
812                         result = g_str_equal(property->value,
813                                                 *((const char **) value));
814         }
815
816         __connman_element_unlock(element);
817
818         return result;
819 }
820
821 int __connman_element_append_ipv4(struct connman_element *element,
822                                                 DBusMessageIter *dict)
823 {
824         const char *method = NULL;
825         const char *address = NULL, *netmask = NULL, *gateway = NULL;
826
827         connman_element_get_value(element,
828                                 CONNMAN_PROPERTY_ID_IPV4_METHOD, &method);
829
830         connman_element_get_value(element,
831                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
832         connman_element_get_value(element,
833                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
834         connman_element_get_value(element,
835                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
836
837         if (method != NULL)
838                 connman_dbus_dict_append_variant(dict, "IPv4.Method",
839                                                 DBUS_TYPE_STRING, &method);
840
841         if (address != NULL)
842                 connman_dbus_dict_append_variant(dict, "IPv4.Address",
843                                                 DBUS_TYPE_STRING, &address);
844
845         if (netmask != NULL)
846                 connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
847                                                 DBUS_TYPE_STRING, &netmask);
848
849         if (gateway != NULL)
850                 connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
851                                                 DBUS_TYPE_STRING, &gateway);
852
853         return 0;
854 }
855
856 int __connman_element_set_ipv4(struct connman_element *element,
857                                 const char *name, DBusMessageIter *value)
858 {
859         int type;
860
861         type = dbus_message_iter_get_arg_type(value);
862
863         if (g_str_equal(name, "IPv4.Method") == TRUE) {
864                 enum connman_ipv4_method method;
865                 const char *str;
866
867                 if (type != DBUS_TYPE_STRING)
868                         return -EINVAL;
869
870                 dbus_message_iter_get_basic(value, &str);
871                 method = __connman_ipv4_string2method(str);
872                 if (method == CONNMAN_IPV4_METHOD_UNKNOWN)
873                         return -EINVAL;
874
875                 if (method == element->ipv4.method)
876                         return -EALREADY;
877
878                 element->ipv4.method = method;
879
880                 connman_element_update(element);
881         } else if (g_str_equal(name, "IPv4.Address") == TRUE) {
882                 const char *address;
883
884                 if (type != DBUS_TYPE_STRING)
885                         return -EINVAL;
886
887                 dbus_message_iter_get_basic(value, &address);
888
889                 g_free(element->ipv4.address);
890                 element->ipv4.address = g_strdup(address);
891
892                 connman_element_update(element);
893         } else if (g_str_equal(name, "IPv4.Netmask") == TRUE) {
894                 const char *netmask;
895
896                 if (type != DBUS_TYPE_STRING)
897                         return -EINVAL;
898
899                 dbus_message_iter_get_basic(value, &netmask);
900
901                 g_free(element->ipv4.netmask);
902                 element->ipv4.netmask = g_strdup(netmask);
903
904                 connman_element_update(element);
905         } else if (g_str_equal(name, "IPv4.Gateway") == TRUE) {
906                 const char *gateway;
907
908                 if (type != DBUS_TYPE_STRING)
909                         return -EINVAL;
910
911                 dbus_message_iter_get_basic(value, &gateway);
912
913                 g_free(element->ipv4.gateway);
914                 element->ipv4.gateway = g_strdup(gateway);
915
916                 connman_element_update(element);
917         }
918
919         return 0;
920 }
921
922 static void append_connections(DBusMessageIter *entry)
923 {
924         DBusMessageIter value, iter;
925         const char *key = "Connections";
926
927         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
928
929         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
930                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
931                                                                 &value);
932
933         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
934                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
935         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
936         dbus_message_iter_close_container(&value, &iter);
937
938         dbus_message_iter_close_container(entry, &value);
939 }
940
941 static void emit_connections_signal(DBusConnection *conn)
942 {
943         DBusMessage *signal;
944         DBusMessageIter entry;
945
946         DBG("conn %p", conn);
947
948         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
949                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
950         if (signal == NULL)
951                 return;
952
953         dbus_message_iter_init_append(signal, &entry);
954
955         append_connections(&entry);
956
957         g_dbus_send_message(conn, signal);
958 }
959
960 static void append_state(DBusMessageIter *entry, const char *state)
961 {
962         DBusMessageIter value;
963         const char *key = "State";
964
965         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
966
967         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
968                                         DBUS_TYPE_STRING_AS_STRING, &value);
969         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
970         dbus_message_iter_close_container(entry, &value);
971 }
972
973 static void emit_state_change(DBusConnection *conn, const char *state)
974 {
975         DBusMessage *signal;
976         DBusMessageIter entry;
977
978         DBG("conn %p", conn);
979
980         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
981                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
982         if (signal == NULL)
983                 return;
984
985         dbus_message_iter_init_append(signal, &entry);
986
987         append_state(&entry, state);
988
989         g_dbus_send_message(conn, signal);
990 }
991
992 static void probe_element(struct connman_element *element)
993 {
994         GSList *list;
995
996         DBG("element %p name %s", element, element->name);
997
998         for (list = driver_list; list; list = list->next) {
999                 struct connman_driver *driver = list->data;
1000
1001                 if (match_driver(element, driver) == FALSE)
1002                         continue;
1003
1004                 DBG("driver %p name %s", driver, driver->name);
1005
1006                 if (driver->probe(element) == 0) {
1007                         __connman_element_lock(element);
1008                         element->driver = driver;
1009                         __connman_element_unlock(element);
1010                         break;
1011                 }
1012         }
1013 }
1014
1015 static void register_element(gpointer data, gpointer user_data)
1016 {
1017         struct connman_element *element = data;
1018         const gchar *basepath;
1019         GNode *node;
1020
1021         __connman_element_lock(element);
1022
1023         if (element->parent) {
1024                 node = g_node_find(element_root, G_PRE_ORDER,
1025                                         G_TRAVERSE_ALL, element->parent);
1026                 basepath = element->parent->path;
1027         } else {
1028                 element->parent = element_root->data;
1029
1030                 node = element_root;
1031                 basepath = "";
1032         }
1033
1034         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1035
1036         __connman_element_unlock(element);
1037
1038         DBG("element %p path %s", element, element->path);
1039
1040         g_node_append_data(node, element);
1041
1042         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1043                 emit_connections_signal(connection);
1044                 emit_state_change(connection, "online");
1045         }
1046
1047         emit_element_signal(connection, "ElementAdded", element);
1048
1049         if (started == FALSE)
1050                 return;
1051
1052         probe_element(element);
1053 }
1054
1055 /**
1056  * connman_element_register:
1057  * @element: the element to register
1058  * @parent: the parent to register the element with
1059  *
1060  * Register an element with the core. It will be register under the given
1061  * parent of if %NULL is provided under the root element.
1062  *
1063  * Returns: %0 on success
1064  */
1065 int connman_element_register(struct connman_element *element,
1066                                         struct connman_element *parent)
1067 {
1068         DBG("element %p name %s parent %p", element, element->name, parent);
1069
1070         if (element->devname == NULL)
1071                 element->devname = g_strdup(element->name);
1072
1073         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1074                 if (g_pattern_match_simple(device_filter,
1075                                                 element->devname) == FALSE) {
1076                         DBG("ignoring %s [%s] device", element->name,
1077                                                         element->devname);
1078                         return -EPERM;
1079                 }
1080         }
1081
1082         if (connman_element_ref(element) == NULL)
1083                 return -EINVAL;
1084
1085         __connman_element_lock(element);
1086
1087         if (element->name == NULL) {
1088                 element->name = g_strdup(type2string(element->type));
1089                 if (element->name == NULL) {
1090                         __connman_element_unlock(element);
1091                         return -EINVAL;
1092                 }
1093         }
1094
1095         if (element->type == CONNMAN_ELEMENT_TYPE_DHCP)
1096                 element->ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
1097
1098         element->parent = parent;
1099
1100         __connman_element_unlock(element);
1101
1102         register_element(element, NULL);
1103
1104         return 0;
1105 }
1106
1107 static gboolean remove_element(GNode *node, gpointer user_data)
1108 {
1109         struct connman_element *element = node->data;
1110         struct connman_element *root = user_data;
1111
1112         DBG("element %p name %s", element, element->name);
1113
1114         if (element == root)
1115                 return FALSE;
1116
1117         if (node != NULL)
1118                 g_node_unlink(node);
1119
1120         if (element->driver) {
1121                 if (element->driver->remove)
1122                         element->driver->remove(element);
1123
1124                 __connman_element_lock(element);
1125                 element->driver = NULL;
1126                 __connman_element_unlock(element);
1127         }
1128
1129         if (node != NULL)
1130                 g_node_destroy(node);
1131
1132         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1133                 if (__connman_element_count(NULL,
1134                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1135                         emit_state_change(connection, "offline");
1136                 emit_connections_signal(connection);
1137         }
1138
1139         emit_element_signal(connection, "ElementRemoved", element);
1140
1141         connman_element_unref(element);
1142
1143         return FALSE;
1144 }
1145
1146 void connman_element_unregister(struct connman_element *element)
1147 {
1148         GNode *node;
1149
1150         DBG("element %p name %s", element, element->name);
1151
1152         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1153
1154         if (node != NULL)
1155                 g_node_traverse(node, G_POST_ORDER,
1156                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1157 }
1158
1159 void connman_element_unregister_children(struct connman_element *element)
1160 {
1161         GNode *node;
1162
1163         DBG("element %p name %s", element, element->name);
1164
1165         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1166
1167         if (node != NULL)
1168                 g_node_traverse(node, G_POST_ORDER,
1169                                 G_TRAVERSE_ALL, -1, remove_element, element);
1170 }
1171
1172 static gboolean update_element(GNode *node, gpointer user_data)
1173 {
1174         struct connman_element *element = node->data;
1175
1176         DBG("element %p name %s", element, element->name);
1177
1178         if (element->driver && element->driver->update)
1179                 element->driver->update(element);
1180
1181         emit_element_signal(connection, "ElementUpdated", element);
1182
1183         return FALSE;
1184 }
1185
1186 void connman_element_update(struct connman_element *element)
1187 {
1188         GNode *node;
1189
1190         DBG("element %p name %s", element, element->name);
1191
1192         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1193
1194         if (node != NULL)
1195                 g_node_traverse(node, G_PRE_ORDER,
1196                                 G_TRAVERSE_ALL, -1, update_element, element);
1197 }
1198
1199 int connman_element_set_enabled(struct connman_element *element,
1200                                                         gboolean enabled)
1201 {
1202         if (element->enabled == enabled)
1203                 return 0;
1204
1205         element->enabled = enabled;
1206
1207         return 0;
1208 }
1209
1210 int __connman_element_init(DBusConnection *conn, const char *device)
1211 {
1212         struct connman_element *element;
1213
1214         DBG("conn %p", conn);
1215
1216         connection = dbus_connection_ref(conn);
1217         if (connection == NULL)
1218                 return -EIO;
1219
1220         device_filter = g_strdup(device);
1221
1222         element = connman_element_create("root");
1223
1224         element->path = g_strdup("/");
1225         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1226
1227         element_root = g_node_new(element);
1228
1229         __connman_network_init();
1230         __connman_device_init();
1231
1232         return 0;
1233 }
1234
1235 static gboolean probe_node(GNode *node, gpointer data)
1236 {
1237         struct connman_element *element = node->data;
1238
1239         DBG("element %p name %s", element, element->name);
1240
1241         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1242                 return FALSE;
1243
1244         if (element->driver)
1245                 return FALSE;
1246
1247         probe_element(element);
1248
1249         return FALSE;
1250 }
1251
1252 void __connman_element_start(void)
1253 {
1254         DBG("");
1255
1256         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1257                                                         probe_node, NULL);
1258
1259         started = TRUE;
1260
1261         __connman_storage_init_device();
1262
1263         __connman_connection_init();
1264         __connman_ipv4_init();
1265         __connman_detect_init();
1266 }
1267
1268 void __connman_element_stop(void)
1269 {
1270         DBG("");
1271
1272         __connman_detect_cleanup();
1273         __connman_ipv4_cleanup();
1274         __connman_connection_cleanup();
1275 }
1276
1277 static gboolean free_driver(GNode *node, gpointer data)
1278 {
1279         struct connman_element *element = node->data;
1280
1281         DBG("element %p name %s", element, element->name);
1282
1283         if (element->driver) {
1284                 if (element->driver->remove)
1285                         element->driver->remove(element);
1286
1287                 __connman_element_lock(element);
1288                 element->driver = NULL;
1289                 __connman_element_unlock(element);
1290         }
1291
1292         return FALSE;
1293 }
1294
1295 static gboolean free_node(GNode *node, gpointer data)
1296 {
1297         struct connman_element *element = node->data;
1298
1299         DBG("element %p name %s", element, element->name);
1300
1301         if (g_node_depth(node) > 1)
1302                 connman_element_unregister(element);
1303
1304         return FALSE;
1305 }
1306
1307 void __connman_element_cleanup(void)
1308 {
1309         DBG("");
1310
1311         __connman_device_cleanup();
1312         __connman_network_cleanup();
1313
1314         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1315                                                         free_driver, NULL);
1316
1317         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1318                                                         free_node, NULL);
1319
1320         g_node_destroy(element_root);
1321         element_root = NULL;
1322
1323         g_free(device_filter);
1324
1325         dbus_connection_unref(connection);
1326 }