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