Add helper for invalid service error messages
[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_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 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_IPV4_METHOD_UNKNOWN)
707                         return connman_element_get_value(element->parent,
708                                                                 id, value);
709                 __connman_element_lock(element);
710                 *((const char **) value) = __connman_ipv4_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
943         connman_element_get_value(element,
944                                 CONNMAN_PROPERTY_ID_IPV4_METHOD, &method);
945
946         connman_element_get_value(element,
947                                 CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address);
948         connman_element_get_value(element,
949                                 CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask);
950         connman_element_get_value(element,
951                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
952
953         if (method != NULL)
954                 connman_dbus_dict_append_variant(dict, "IPv4.Method",
955                                                 DBUS_TYPE_STRING, &method);
956
957         if (address != NULL)
958                 connman_dbus_dict_append_variant(dict, "IPv4.Address",
959                                                 DBUS_TYPE_STRING, &address);
960
961         if (netmask != NULL)
962                 connman_dbus_dict_append_variant(dict, "IPv4.Netmask",
963                                                 DBUS_TYPE_STRING, &netmask);
964
965         if (gateway != NULL)
966                 connman_dbus_dict_append_variant(dict, "IPv4.Gateway",
967                                                 DBUS_TYPE_STRING, &gateway);
968
969         return 0;
970 }
971
972 int __connman_element_set_ipv4(struct connman_element *element,
973                                 const char *name, DBusMessageIter *value)
974 {
975         int type;
976
977         type = dbus_message_iter_get_arg_type(value);
978
979         if (g_str_equal(name, "IPv4.Method") == TRUE) {
980                 enum connman_ipv4_method method;
981                 const char *str;
982
983                 if (type != DBUS_TYPE_STRING)
984                         return -EINVAL;
985
986                 dbus_message_iter_get_basic(value, &str);
987                 method = __connman_ipv4_string2method(str);
988                 if (method == CONNMAN_IPV4_METHOD_UNKNOWN)
989                         return -EINVAL;
990
991                 if (method == element->ipv4.method)
992                         return -EALREADY;
993
994                 element->ipv4.method = method;
995
996                 connman_element_update(element);
997         } else if (g_str_equal(name, "IPv4.Address") == TRUE) {
998                 const char *address;
999
1000                 if (type != DBUS_TYPE_STRING)
1001                         return -EINVAL;
1002
1003                 dbus_message_iter_get_basic(value, &address);
1004
1005                 g_free(element->ipv4.address);
1006                 element->ipv4.address = g_strdup(address);
1007
1008                 connman_element_update(element);
1009         } else if (g_str_equal(name, "IPv4.Netmask") == TRUE) {
1010                 const char *netmask;
1011
1012                 if (type != DBUS_TYPE_STRING)
1013                         return -EINVAL;
1014
1015                 dbus_message_iter_get_basic(value, &netmask);
1016
1017                 g_free(element->ipv4.netmask);
1018                 element->ipv4.netmask = g_strdup(netmask);
1019
1020                 connman_element_update(element);
1021         } else if (g_str_equal(name, "IPv4.Gateway") == TRUE) {
1022                 const char *gateway;
1023
1024                 if (type != DBUS_TYPE_STRING)
1025                         return -EINVAL;
1026
1027                 dbus_message_iter_get_basic(value, &gateway);
1028
1029                 g_free(element->ipv4.gateway);
1030                 element->ipv4.gateway = g_strdup(gateway);
1031
1032                 connman_element_update(element);
1033         }
1034
1035         return 0;
1036 }
1037
1038 static void append_state(DBusMessageIter *entry, const char *state)
1039 {
1040         DBusMessageIter value;
1041         const char *key = "State";
1042
1043         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
1044
1045         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
1046                                         DBUS_TYPE_STRING_AS_STRING, &value);
1047         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &state);
1048         dbus_message_iter_close_container(entry, &value);
1049 }
1050
1051 static void emit_state_change(DBusConnection *conn, const char *state)
1052 {
1053         DBusMessage *signal;
1054         DBusMessageIter entry;
1055
1056         DBG("conn %p", conn);
1057
1058         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1059                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1060         if (signal == NULL)
1061                 return;
1062
1063         dbus_message_iter_init_append(signal, &entry);
1064
1065         append_state(&entry, state);
1066
1067         g_dbus_send_message(conn, signal);
1068 }
1069
1070 static void probe_element(struct connman_element *element)
1071 {
1072         GSList *list;
1073
1074         DBG("element %p name %s", element, element->name);
1075
1076         for (list = driver_list; list; list = list->next) {
1077                 struct connman_driver *driver = list->data;
1078
1079                 if (match_driver(element, driver) == FALSE)
1080                         continue;
1081
1082                 DBG("driver %p name %s", driver, driver->name);
1083
1084                 if (driver->probe(element) == 0) {
1085                         __connman_element_lock(element);
1086                         element->driver = driver;
1087                         __connman_element_unlock(element);
1088                         break;
1089                 }
1090         }
1091 }
1092
1093 static void register_element(gpointer data, gpointer user_data)
1094 {
1095         struct connman_element *element = data;
1096         const gchar *basepath;
1097         GNode *node;
1098
1099         __connman_element_lock(element);
1100
1101         if (element->parent) {
1102                 node = g_node_find(element_root, G_PRE_ORDER,
1103                                         G_TRAVERSE_ALL, element->parent);
1104                 basepath = element->parent->path;
1105         } else {
1106                 element->parent = element_root->data;
1107
1108                 node = element_root;
1109                 basepath = "";
1110         }
1111
1112         element->path = g_strdup_printf("%s/%s", basepath, element->name);
1113
1114         __connman_element_unlock(element);
1115
1116         DBG("element %p path %s", element, element->path);
1117
1118         g_node_append_data(node, element);
1119
1120         if (element->type == CONNMAN_ELEMENT_TYPE_DHCP) {
1121                 element->parent->configuring = TRUE;
1122
1123                 if (__connman_element_count(NULL,
1124                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1125                         emit_state_change(connection, "connecting");
1126         }
1127
1128         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1129                 struct connman_element *parent = element->parent;
1130
1131                 while (parent) {
1132                         parent->configuring = FALSE;
1133                         parent = parent->parent;
1134                 }
1135
1136                 if (__connman_element_count(NULL,
1137                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 1)
1138                         emit_state_change(connection, "online");
1139         }
1140
1141         emit_element_signal(connection, "ElementAdded", element);
1142
1143         if (started == FALSE)
1144                 return;
1145
1146         probe_element(element);
1147 }
1148
1149 /**
1150  * connman_element_register:
1151  * @element: the element to register
1152  * @parent: the parent to register the element with
1153  *
1154  * Register an element with the core. It will be register under the given
1155  * parent of if %NULL is provided under the root element.
1156  *
1157  * Returns: %0 on success
1158  */
1159 int connman_element_register(struct connman_element *element,
1160                                         struct connman_element *parent)
1161 {
1162         DBG("element %p name %s parent %p", element, element->name, parent);
1163
1164         if (element->devname == NULL)
1165                 element->devname = g_strdup(element->name);
1166
1167         if (device_filter && element->type == CONNMAN_ELEMENT_TYPE_DEVICE) {
1168                 if (g_pattern_match_simple(device_filter,
1169                                                 element->devname) == FALSE) {
1170                         DBG("ignoring %s [%s] device", element->name,
1171                                                         element->devname);
1172                         return -EPERM;
1173                 }
1174         }
1175
1176         if (connman_element_ref(element) == NULL)
1177                 return -EINVAL;
1178
1179         __connman_element_lock(element);
1180
1181         if (element->name == NULL) {
1182                 element->name = g_strdup(type2string(element->type));
1183                 if (element->name == NULL) {
1184                         __connman_element_unlock(element);
1185                         return -EINVAL;
1186                 }
1187         }
1188
1189         if (element->type == CONNMAN_ELEMENT_TYPE_DHCP)
1190                 element->ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
1191
1192         element->parent = parent;
1193
1194         __connman_element_unlock(element);
1195
1196         register_element(element, NULL);
1197
1198         return 0;
1199 }
1200
1201 static gboolean remove_element(GNode *node, gpointer user_data)
1202 {
1203         struct connman_element *element = node->data;
1204         struct connman_element *root = user_data;
1205
1206         DBG("element %p name %s", element, element->name);
1207
1208         if (element == root)
1209                 return FALSE;
1210
1211         if (node != NULL)
1212                 g_node_unlink(node);
1213
1214         if (element->driver) {
1215                 if (element->driver->remove)
1216                         element->driver->remove(element);
1217
1218                 __connman_element_lock(element);
1219                 element->driver = NULL;
1220                 __connman_element_unlock(element);
1221         }
1222
1223         if (node != NULL)
1224                 g_node_destroy(node);
1225
1226         if (element->type == CONNMAN_ELEMENT_TYPE_CONNECTION) {
1227                 if (__connman_element_count(NULL,
1228                                         CONNMAN_ELEMENT_TYPE_CONNECTION) == 0)
1229                         emit_state_change(connection, "offline");
1230         }
1231
1232         emit_element_signal(connection, "ElementRemoved", element);
1233
1234         connman_element_unref(element);
1235
1236         return FALSE;
1237 }
1238
1239 void connman_element_unregister(struct connman_element *element)
1240 {
1241         GNode *node;
1242
1243         DBG("element %p name %s", element, element->name);
1244
1245         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1246
1247         if (node != NULL)
1248                 g_node_traverse(node, G_POST_ORDER,
1249                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
1250 }
1251
1252 void connman_element_unregister_children(struct connman_element *element)
1253 {
1254         GNode *node;
1255
1256         DBG("element %p name %s", element, element->name);
1257
1258         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1259
1260         if (node != NULL)
1261                 g_node_traverse(node, G_POST_ORDER,
1262                                 G_TRAVERSE_ALL, -1, remove_element, element);
1263 }
1264
1265 static gboolean update_element(GNode *node, gpointer user_data)
1266 {
1267         struct connman_element *element = node->data;
1268
1269         DBG("element %p name %s", element, element->name);
1270
1271         if (element->driver && element->driver->update)
1272                 element->driver->update(element);
1273
1274         emit_element_signal(connection, "ElementUpdated", element);
1275
1276         return FALSE;
1277 }
1278
1279 void connman_element_update(struct connman_element *element)
1280 {
1281         GNode *node;
1282
1283         DBG("element %p name %s", element, element->name);
1284
1285         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
1286
1287         if (node != NULL)
1288                 g_node_traverse(node, G_PRE_ORDER,
1289                                 G_TRAVERSE_ALL, -1, update_element, element);
1290 }
1291
1292 int connman_element_set_enabled(struct connman_element *element,
1293                                                         gboolean enabled)
1294 {
1295         if (element->enabled == enabled)
1296                 return 0;
1297
1298         element->enabled = enabled;
1299
1300         connman_element_update(element);
1301
1302         return 0;
1303 }
1304
1305 /**
1306  * connman_element_set_error:
1307  * @element: element structure
1308  * @error: error identifier
1309  *
1310  * Set error state and specific error identifier
1311  */
1312 void connman_element_set_error(struct connman_element *element,
1313                                         enum connman_element_error error)
1314 {
1315         struct connman_service *service;
1316
1317         DBG("element %p error %d", element, error);
1318
1319         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1320                 return;
1321
1322         element->state = CONNMAN_ELEMENT_STATE_ERROR;
1323         element->error = error;
1324
1325         if (element->driver && element->driver->change)
1326                 element->driver->change(element);
1327
1328         service = __connman_element_get_service(element);
1329         __connman_service_indicate_state(service,
1330                                         CONNMAN_SERVICE_STATE_FAILURE);
1331 }
1332
1333 int __connman_element_init(DBusConnection *conn, const char *device,
1334                                                         const char *nodevice)
1335 {
1336         struct connman_element *element;
1337
1338         DBG("conn %p", conn);
1339
1340         connection = dbus_connection_ref(conn);
1341         if (connection == NULL)
1342                 return -EIO;
1343
1344         device_filter = g_strdup(device);
1345
1346         element = connman_element_create("root");
1347
1348         element->path = g_strdup("/");
1349         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
1350
1351         element_root = g_node_new(element);
1352
1353         __connman_notifier_init();
1354         __connman_service_init();
1355         __connman_network_init();
1356         __connman_device_init();
1357
1358         return 0;
1359 }
1360
1361 static gboolean probe_node(GNode *node, gpointer data)
1362 {
1363         struct connman_element *element = node->data;
1364
1365         DBG("element %p name %s", element, element->name);
1366
1367         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
1368                 return FALSE;
1369
1370         if (element->driver)
1371                 return FALSE;
1372
1373         probe_element(element);
1374
1375         return FALSE;
1376 }
1377
1378 void __connman_element_start(void)
1379 {
1380         DBG("");
1381
1382         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1383                                                         probe_node, NULL);
1384
1385         started = TRUE;
1386
1387         __connman_storage_init_device();
1388
1389         __connman_connection_init();
1390         __connman_ipv4_init();
1391         __connman_detect_init();
1392 }
1393
1394 void __connman_element_stop(void)
1395 {
1396         DBG("");
1397
1398         __connman_detect_cleanup();
1399         __connman_ipv4_cleanup();
1400         __connman_connection_cleanup();
1401 }
1402
1403 static gboolean free_driver(GNode *node, gpointer data)
1404 {
1405         struct connman_element *element = node->data;
1406
1407         DBG("element %p name %s", element, element->name);
1408
1409         if (element->driver) {
1410                 if (element->driver->remove)
1411                         element->driver->remove(element);
1412
1413                 __connman_element_lock(element);
1414                 element->driver = NULL;
1415                 __connman_element_unlock(element);
1416         }
1417
1418         return FALSE;
1419 }
1420
1421 static gboolean free_node(GNode *node, gpointer data)
1422 {
1423         struct connman_element *element = node->data;
1424
1425         DBG("element %p name %s", element, element->name);
1426
1427         if (g_node_depth(node) > 1)
1428                 connman_element_unregister(element);
1429
1430         return FALSE;
1431 }
1432
1433 void __connman_element_cleanup(void)
1434 {
1435         DBG("");
1436
1437         __connman_device_cleanup();
1438         __connman_network_cleanup();
1439         __connman_service_cleanup();
1440         __connman_notifier_cleanup();
1441
1442         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1443                                                         free_driver, NULL);
1444
1445         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1446                                                         free_node, NULL);
1447
1448         g_node_destroy(element_root);
1449         element_root = NULL;
1450
1451         g_free(device_filter);
1452
1453         dbus_connection_unref(connection);
1454 }