unit: Toggle SessionMode for each test case
[framework/connectivity/connman.git] / src / element.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "connman.h"
34
35 static DBusConnection *connection;
36
37 static GNode *element_root = NULL;
38 static GSList *driver_list = NULL;
39
40 static gboolean started = FALSE;
41
42 static const char *type2string(enum connman_element_type type)
43 {
44         switch (type) {
45         case CONNMAN_ELEMENT_TYPE_UNKNOWN:
46                 return "unknown";
47         case CONNMAN_ELEMENT_TYPE_ROOT:
48                 return "root";
49         case CONNMAN_ELEMENT_TYPE_NETWORK:
50                 return "network";
51         }
52
53         return NULL;
54 }
55
56 struct foreach_data {
57         enum connman_element_type type;
58         element_cb_t callback;
59         gpointer user_data;
60 };
61
62 static gboolean foreach_callback(GNode *node, gpointer user_data)
63 {
64         struct connman_element *element = node->data;
65         struct foreach_data *data = user_data;
66
67         DBG("element %p name %s", element, element->name);
68
69         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
70                 return FALSE;
71
72         if (data->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
73                                         data->type != element->type)
74                 return FALSE;
75
76         if (data->callback)
77                 data->callback(element, data->user_data);
78
79         return FALSE;
80 }
81
82 void __connman_element_foreach(struct connman_element *element,
83                                 enum connman_element_type type,
84                                 element_cb_t callback, gpointer user_data)
85 {
86         struct foreach_data data = { type, callback, user_data };
87         GNode *node;
88
89         DBG("");
90
91         if (element != NULL) {
92                 node = g_node_find(element_root, G_PRE_ORDER,
93                                                 G_TRAVERSE_ALL, element);
94                 if (node == NULL)
95                         return;
96         } else
97                 node = element_root;
98
99         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
100                                                 foreach_callback, &data);
101 }
102
103 struct append_filter {
104         enum connman_element_type type;
105         DBusMessageIter *iter;
106 };
107
108 static gboolean append_path(GNode *node, gpointer user_data)
109 {
110         struct connman_element *element = node->data;
111         struct append_filter *filter = user_data;
112
113         DBG("element %p name %s", element, element->name);
114
115         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
116                 return FALSE;
117
118         if (filter->type != CONNMAN_ELEMENT_TYPE_UNKNOWN &&
119                                         filter->type != element->type)
120                 return FALSE;
121
122         if (filter->type == CONNMAN_ELEMENT_TYPE_NETWORK &&
123                         __connman_network_has_driver(element->network) == FALSE)
124                 return FALSE;
125
126         dbus_message_iter_append_basic(filter->iter,
127                                 DBUS_TYPE_OBJECT_PATH, &element->path);
128
129         return FALSE;
130 }
131
132 void __connman_element_list(struct connman_element *element,
133                                         enum connman_element_type type,
134                                                         DBusMessageIter *iter)
135 {
136         struct append_filter filter = { type, iter };
137         GNode *node;
138
139         DBG("");
140
141         if (element != NULL) {
142                 node = g_node_find(element_root, G_PRE_ORDER,
143                                                 G_TRAVERSE_ALL, element);
144                 if (node == NULL)
145                         return;
146         } else
147                 node = element_root;
148
149         g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
150                                                 append_path, &filter);
151 }
152
153 static gint compare_priority(gconstpointer a, gconstpointer b)
154 {
155         const struct connman_driver *driver1 = a;
156         const struct connman_driver *driver2 = b;
157
158         return driver2->priority - driver1->priority;
159 }
160
161 static gboolean match_driver(struct connman_element *element,
162                                         struct connman_driver *driver)
163 {
164         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
165                 return FALSE;
166
167         if (element->type == driver->type ||
168                         driver->type == CONNMAN_ELEMENT_TYPE_UNKNOWN)
169                 return TRUE;
170
171         return FALSE;
172 }
173
174 static gboolean probe_driver(GNode *node, gpointer data)
175 {
176         struct connman_element *element = node->data;
177         struct connman_driver *driver = data;
178
179         DBG("element %p name %s", element, element->name);
180
181         if (!element->driver && match_driver(element, driver) == TRUE) {
182                 if (driver->probe(element) < 0)
183                         return FALSE;
184
185                 element->driver = driver;
186         }
187
188         return FALSE;
189 }
190
191 void __connman_driver_rescan(struct connman_driver *driver)
192 {
193         DBG("driver %p name %s", driver, driver->name);
194
195         if (!driver->probe)
196                 return;
197
198         if (element_root != NULL)
199                 g_node_traverse(element_root, G_PRE_ORDER,
200                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
201 }
202
203 /**
204  * connman_driver_register:
205  * @driver: driver definition
206  *
207  * Register a new driver
208  *
209  * Returns: %0 on success
210  */
211 int connman_driver_register(struct connman_driver *driver)
212 {
213         DBG("driver %p name %s", driver, driver->name);
214
215         if (driver->type == CONNMAN_ELEMENT_TYPE_ROOT)
216                 return -EINVAL;
217
218         if (!driver->probe)
219                 return -EINVAL;
220
221         driver_list = g_slist_insert_sorted(driver_list, driver,
222                                                         compare_priority);
223
224         if (started == FALSE)
225                 return 0;
226
227         if (element_root != NULL)
228                 g_node_traverse(element_root, G_PRE_ORDER,
229                                 G_TRAVERSE_ALL, -1, probe_driver, driver);
230
231         return 0;
232 }
233
234 static gboolean remove_driver(GNode *node, gpointer data)
235 {
236         struct connman_element *element = node->data;
237         struct connman_driver *driver = data;
238
239         DBG("element %p name %s", element, element->name);
240
241         if (element->driver == driver) {
242                 if (driver->remove)
243                         driver->remove(element);
244
245                 element->driver = NULL;
246         }
247
248         return FALSE;
249 }
250
251 /**
252  * connman_driver_unregister:
253  * @driver: driver definition
254  *
255  * Remove a previously registered driver
256  */
257 void connman_driver_unregister(struct connman_driver *driver)
258 {
259         DBG("driver %p name %s", driver, driver->name);
260
261         driver_list = g_slist_remove(driver_list, driver);
262
263         if (element_root != NULL)
264                 g_node_traverse(element_root, G_POST_ORDER,
265                                 G_TRAVERSE_ALL, -1, remove_driver, driver);
266 }
267
268 static void unregister_property(gpointer data)
269 {
270         struct connman_property *property = data;
271
272         DBG("property %p", property);
273
274         g_free(property->value);
275         g_free(property);
276 }
277
278 static void unregister_child(gpointer data)
279 {
280         struct connman_element *element = data;
281
282         DBG("element %p", element);
283
284         connman_element_unref(element);
285 }
286
287 void __connman_element_initialize(struct connman_element *element)
288 {
289         DBG("element %p", element);
290
291         element->refcount = 1;
292
293         element->name    = NULL;
294         element->type    = CONNMAN_ELEMENT_TYPE_UNKNOWN;
295         element->state   = CONNMAN_ELEMENT_STATE_UNKNOWN;
296         element->error   = CONNMAN_ELEMENT_ERROR_UNKNOWN;
297         element->index   = -1;
298         element->enabled = FALSE;
299
300         element->children = g_hash_table_new_full(g_str_hash, g_str_equal,
301                                                 NULL, unregister_child);
302
303         element->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
304                                                 g_free, unregister_property);
305 }
306
307 /**
308  * connman_element_create:
309  * @name: element name
310  *
311  * Allocate a new element and assign the given #name to it. If the name
312  * is #NULL, it will be later on created based on the element type.
313  *
314  * Returns: a newly-allocated #connman_element structure
315  */
316 struct connman_element *connman_element_create(const char *name)
317 {
318         struct connman_element *element;
319
320         element = g_try_new0(struct connman_element, 1);
321         if (element == NULL)
322                 return NULL;
323
324         DBG("element %p", element);
325
326         __connman_element_initialize(element);
327
328         element->name = g_strdup(name);
329
330         return element;
331 }
332
333 struct connman_element *connman_element_ref(struct connman_element *element)
334 {
335         DBG("element %p name %s refcount %d", element, element->name,
336                                 g_atomic_int_get(&element->refcount) + 1);
337
338         g_atomic_int_inc(&element->refcount);
339
340         return element;
341 }
342
343 static void free_properties(struct connman_element *element)
344 {
345         DBG("element %p name %s", element, element->name);
346
347         g_hash_table_destroy(element->properties);
348         element->properties = NULL;
349 }
350
351 static void free_children(struct connman_element *element)
352 {
353         DBG("element %p name %s", element, element->name);
354
355         g_hash_table_destroy(element->children);
356         element->children = NULL;
357 }
358
359 void connman_element_unref(struct connman_element *element)
360 {
361         DBG("element %p name %s refcount %d", element, element->name,
362                                 g_atomic_int_get(&element->refcount) - 1);
363
364         if (g_atomic_int_dec_and_test(&element->refcount) == TRUE) {
365                 if (element->destruct)
366                         element->destruct(element);
367                 free_children(element);
368                 free_properties(element);
369                 g_free(element->devname);
370                 g_free(element->path);
371                 g_free(element->name);
372                 g_free(element);
373         }
374 }
375
376 static int set_static_property(struct connman_element *element,
377                                 const char *name, int type, const void *value)
378 {
379         struct connman_property *property;
380
381         DBG("element %p name %s", element, element->name);
382
383         if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_BYTE)
384                 return -EINVAL;
385
386         property = g_try_new0(struct connman_property, 1);
387         if (property == NULL)
388                 return -ENOMEM;
389
390         property->id   = CONNMAN_PROPERTY_ID_INVALID;
391         property->type = type;
392
393         DBG("name %s type %d value %p", name, type, value);
394
395         switch (type) {
396         case DBUS_TYPE_STRING:
397                 property->value = g_strdup(*((const char **) value));
398                 break;
399         case DBUS_TYPE_BOOLEAN:
400         case DBUS_TYPE_BYTE:
401                 property->value = g_try_malloc(1);
402                 if (property->value != NULL)
403                         memcpy(property->value, value, 1);
404                 break;
405         }
406
407         g_hash_table_replace(element->properties, g_strdup(name), property);
408
409         return 0;
410 }
411
412 static int set_static_array_property(struct connman_element *element,
413                         const char *name, int type, const void *value, int len)
414 {
415         struct connman_property *property;
416
417         DBG("element %p name %s", element, element->name);
418
419         if (type != DBUS_TYPE_BYTE)
420                 return -EINVAL;
421
422         property = g_try_new0(struct connman_property, 1);
423         if (property == NULL)
424                 return -ENOMEM;
425
426         property->id      = CONNMAN_PROPERTY_ID_INVALID;
427         property->type    = DBUS_TYPE_ARRAY;
428         property->subtype = type;
429
430         DBG("name %s type %d value %p", name, type, value);
431
432         switch (type) {
433         case DBUS_TYPE_BYTE:
434                 property->value = g_try_malloc(len);
435                 if (property->value != NULL) {
436                         memcpy(property->value,
437                                 *((const unsigned char **) value), len);
438                         property->size = len;
439                 }
440                 break;
441         }
442
443         g_hash_table_replace(element->properties, g_strdup(name), property);
444
445         return 0;
446 }
447
448 int connman_element_get_value(struct connman_element *element,
449                                 enum connman_property_id id, void *value)
450 {
451         return -EINVAL;
452 }
453
454 static gboolean get_static_property(struct connman_element *element,
455                                                 const char *name, void *value)
456 {
457         struct connman_property *property;
458         gboolean found = FALSE;
459
460         DBG("element %p name %s", element, element->name);
461
462         property = g_hash_table_lookup(element->properties, name);
463         if (property != NULL) {
464                 switch (property->type) {
465                 case DBUS_TYPE_STRING:
466                         *((char **) value) = property->value;
467                         found = TRUE;
468                         break;
469                 case DBUS_TYPE_BOOLEAN:
470                 case DBUS_TYPE_BYTE:
471                         memcpy(value, property->value, 1);
472                         found = TRUE;
473                         break;
474                 }
475         }
476
477         if (found == FALSE && element->parent != NULL)
478                 return get_static_property(element->parent, name, value);
479
480         return found;
481 }
482
483 static gboolean get_static_array_property(struct connman_element *element,
484                         const char *name, void *value, unsigned int *len)
485 {
486         struct connman_property *property;
487         gboolean found = FALSE;
488
489         DBG("element %p name %s", element, element->name);
490
491         property = g_hash_table_lookup(element->properties, name);
492         if (property != NULL) {
493                 *((void **) value) = property->value;
494                 *len = property->size;
495                 found = TRUE;
496         }
497
498         return found;
499 }
500
501 /**
502  * connman_element_set_string:
503  * @element: element structure
504  * @key: unique identifier
505  * @value: string value
506  *
507  * Set string value for specific key
508  */
509 int connman_element_set_string(struct connman_element *element,
510                                         const char *key, const char *value)
511 {
512         return set_static_property(element, key, DBUS_TYPE_STRING, &value);
513 }
514
515 /**
516  * connman_element_get_string:
517  * @element: element structure
518  * @key: unique identifier
519  *
520  * Get string value for specific key
521  */
522 const char *connman_element_get_string(struct connman_element *element,
523                                                         const char *key)
524 {
525         const char *value;
526
527         if (get_static_property(element, key, &value) == FALSE)
528                 return NULL;
529
530         return value;
531 }
532
533 /**
534  * connman_element_set_bool:
535  * @element: element structure
536  * @key: unique identifier
537  * @value: boolean value
538  *
539  * Set boolean value for specific key
540  */
541 int connman_element_set_bool(struct connman_element *element,
542                                         const char *key, connman_bool_t value)
543 {
544         return set_static_property(element, key, DBUS_TYPE_BOOLEAN, &value);
545 }
546
547 /**
548  * connman_element_get_bool:
549  * @element: element structure
550  * @key: unique identifier
551  *
552  * Get boolean value for specific key
553  */
554 connman_bool_t connman_element_get_bool(struct connman_element *element,
555                                                         const char *key)
556 {
557         connman_bool_t value;
558
559         if (get_static_property(element, key, &value) == FALSE)
560                 return FALSE;
561
562         return value;
563 }
564
565 /**
566  * connman_element_set_uint8:
567  * @element: element structure
568  * @key: unique identifier
569  * @value: integer value
570  *
571  * Set integer value for specific key
572  */
573 int connman_element_set_uint8(struct connman_element *element,
574                                         const char *key, connman_uint8_t value)
575 {
576         return set_static_property(element, key, DBUS_TYPE_BYTE, &value);
577 }
578
579 /**
580  * connman_element_get_uint8:
581  * @element: element structure
582  * @key: unique identifier
583  *
584  * Get integer value for specific key
585  */
586 connman_uint8_t connman_element_get_uint8(struct connman_element *element,
587                                                         const char *key)
588 {
589         connman_uint8_t value;
590
591         if (get_static_property(element, key, &value) == FALSE)
592                 return 0;
593
594         return value;
595 }
596
597 /**
598  * connman_element_set_blob:
599  * @element: element structure
600  * @key: unique identifier
601  * @data: blob data
602  * @size: blob size
603  *
604  * Set binary blob value for specific key
605  */
606 int connman_element_set_blob(struct connman_element *element,
607                         const char *key, const void *data, unsigned int size)
608 {
609         return set_static_array_property(element, key,
610                                                 DBUS_TYPE_BYTE, &data, size);
611 }
612
613 /**
614  * connman_element_get_blob:
615  * @element: element structure
616  * @key: unique identifier
617  * @size: pointer to blob size
618  *
619  * Get binary blob value for specific key
620  */
621 const void *connman_element_get_blob(struct connman_element *element,
622                                         const char *key, unsigned int *size)
623 {
624         void *value;
625
626         if (get_static_array_property(element, key, &value, size) == FALSE)
627                 return NULL;
628
629         return value;
630 }
631
632 static void probe_element(struct connman_element *element)
633 {
634         GSList *list;
635
636         DBG("element %p name %s", element, element->name);
637
638         for (list = driver_list; list; list = list->next) {
639                 struct connman_driver *driver = list->data;
640
641                 if (match_driver(element, driver) == FALSE)
642                         continue;
643
644                 DBG("driver %p name %s", driver, driver->name);
645
646                 if (driver->probe(element) == 0) {
647                         element->driver = driver;
648                         break;
649                 }
650         }
651 }
652
653 static void register_element(gpointer data, gpointer user_data)
654 {
655         struct connman_element *element = data;
656         const gchar *basepath;
657         GNode *node;
658
659         if (element->parent) {
660                 node = g_node_find(element_root, G_PRE_ORDER,
661                                         G_TRAVERSE_ALL, element->parent);
662                 basepath = element->parent->path;
663         } else {
664                 element->parent = element_root->data;
665
666                 node = element_root;
667                 basepath = CONNMAN_PATH "/device";
668         }
669
670         element->path = g_strdup_printf("%s/%s", basepath, element->name);
671
672         if (node == NULL) {
673                 connman_error("Element registration for %s failed",
674                                                         element->path);
675                 return;
676         }
677
678         DBG("element %p path %s", element, element->path);
679
680         g_node_append_data(node, element);
681
682         if (started == FALSE)
683                 return;
684
685         probe_element(element);
686 }
687
688 /**
689  * connman_element_register:
690  * @element: the element to register
691  * @parent: the parent to register the element with
692  *
693  * Register an element with the core. It will be register under the given
694  * parent of if %NULL is provided under the root element.
695  *
696  * Returns: %0 on success
697  */
698 int connman_element_register(struct connman_element *element,
699                                         struct connman_element *parent)
700 {
701         DBG("element %p name %s parent %p", element, element->name, parent);
702
703         if (element->devname == NULL)
704                 element->devname = g_strdup(element->name);
705
706         if (connman_element_ref(element) == NULL)
707                 return -EINVAL;
708
709         if (element->name == NULL) {
710                 element->name = g_strdup(type2string(element->type));
711                 if (element->name == NULL) {
712                         return -EINVAL;
713                 }
714         }
715
716         element->parent = parent;
717
718         register_element(element, NULL);
719
720         return 0;
721 }
722
723 static gboolean remove_element(GNode *node, gpointer user_data)
724 {
725         struct connman_element *element = node->data;
726         struct connman_element *root = user_data;
727
728         DBG("element %p name %s", element, element->name);
729
730         if (element == root)
731                 return FALSE;
732
733         g_node_unlink(node);
734
735         if (element->driver) {
736                 if (element->driver->remove)
737                         element->driver->remove(element);
738
739                 element->driver = NULL;
740         }
741
742         g_node_destroy(node);
743
744         connman_element_unref(element);
745
746         return FALSE;
747 }
748
749 void connman_element_unregister(struct connman_element *element)
750 {
751         GNode *node;
752
753         DBG("element %p name %s", element, element->name);
754
755         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
756
757         if (node != NULL)
758                 g_node_traverse(node, G_POST_ORDER,
759                                 G_TRAVERSE_ALL, -1, remove_element, NULL);
760 }
761
762 void connman_element_unregister_children(struct connman_element *element)
763 {
764         GNode *node;
765
766         DBG("element %p name %s", element, element->name);
767
768         node = g_node_find(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, element);
769
770         if (node != NULL)
771                 g_node_traverse(node, G_POST_ORDER,
772                                 G_TRAVERSE_ALL, -1, remove_element, element);
773 }
774
775 int __connman_element_init()
776 {
777         struct connman_element *element;
778
779         DBG("");
780
781         connection = connman_dbus_get_connection();
782         if (connection == NULL)
783                 return -EIO;
784         element = connman_element_create("root");
785
786         element->path = g_strdup("/");
787         element->type = CONNMAN_ELEMENT_TYPE_ROOT;
788
789         element_root = g_node_new(element);
790
791         __connman_technology_init();
792         __connman_notifier_init();
793         __connman_location_init();
794         __connman_service_init();
795         __connman_provider_init();
796         __connman_network_init();
797
798         return 0;
799 }
800
801 static gboolean probe_node(GNode *node, gpointer data)
802 {
803         struct connman_element *element = node->data;
804
805         DBG("element %p name %s", element, element->name);
806
807         if (element->type == CONNMAN_ELEMENT_TYPE_ROOT)
808                 return FALSE;
809
810         if (element->driver)
811                 return FALSE;
812
813         probe_element(element);
814
815         return FALSE;
816 }
817
818 void __connman_element_start(void)
819 {
820         DBG("");
821
822         __connman_storage_init_profile();
823
824         g_node_traverse(element_root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
825                                                         probe_node, NULL);
826
827         started = TRUE;
828
829         __connman_rtnl_start();
830
831         __connman_dhcp_init();
832         __connman_wpad_init();
833         __connman_wispr_init();
834
835         __connman_rfkill_init();
836 }
837
838 void __connman_element_stop(void)
839 {
840         DBG("");
841
842         __connman_rfkill_cleanup();
843
844         __connman_wispr_cleanup();
845         __connman_wpad_cleanup();
846         __connman_dhcp_cleanup();
847         __connman_provider_cleanup();
848 }
849
850 static gboolean free_driver(GNode *node, gpointer data)
851 {
852         struct connman_element *element = node->data;
853
854         DBG("element %p name %s", element, element->name);
855
856         if (element->driver) {
857                 if (element->driver->remove)
858                         element->driver->remove(element);
859
860                 element->driver = NULL;
861         }
862
863         return FALSE;
864 }
865
866 static gboolean free_node(GNode *node, gpointer data)
867 {
868         struct connman_element *element = node->data;
869
870         DBG("element %p name %s", element, element->name);
871
872         if (g_node_depth(node) > 1)
873                 connman_element_unregister(element);
874
875         return FALSE;
876 }
877
878 void __connman_element_cleanup(void)
879 {
880         DBG("");
881
882         __connman_network_cleanup();
883         __connman_service_cleanup();
884         __connman_location_cleanup();
885         __connman_notifier_cleanup();
886         __connman_technology_cleanup();
887
888         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
889                                                         free_driver, NULL);
890
891         g_node_traverse(element_root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
892                                                         free_node, NULL);
893
894         connman_element_unref(element_root->data);
895
896         g_node_destroy(element_root);
897         element_root = NULL;
898
899         if (connection == NULL)
900                 return;
901
902         dbus_connection_unref(connection);
903 }