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