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