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