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