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