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