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