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