vpn-plugin: Propagate most common errors to callback function
[platform/upstream/connman.git] / plugins / vpn.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012  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 <string.h>
27 #include <errno.h>
28 #include <sys/socket.h>
29 #include <stdlib.h>
30 #include <glib.h>
31
32 #include <gdbus.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/technology.h>
36 #include <connman/plugin.h>
37 #include <connman/log.h>
38 #include <connman/dbus.h>
39 #include <connman/provider.h>
40 #include <connman/ipaddress.h>
41 #include <connman/vpn-dbus.h>
42 #include <connman/inet.h>
43 #include <gweb/gresolv.h>
44
45 #define DBUS_TIMEOUT 10000
46
47 static DBusConnection *connection;
48
49 static GHashTable *vpn_connections = NULL;
50 static guint watch;
51 static guint added_watch;
52 static guint removed_watch;
53 static guint property_watch;
54
55 struct vpn_route {
56         int family;
57         char *network;
58         char *netmask;
59         char *gateway;
60 };
61
62 struct config_create_data {
63         connection_ready_cb callback;
64         DBusMessage *message;
65         char *path;
66 };
67
68 struct connection_data {
69         char *path;
70         char *ident;
71         struct connman_provider *provider;
72         int index;
73         DBusPendingCall *call;
74         connman_bool_t connect_pending;
75         struct config_create_data *cb_data;
76
77         char *state;
78         char *type;
79         char *name;
80         char *host;
81         char **host_ip;
82         char *domain;
83         char **nameservers;
84
85         GHashTable *server_routes;
86         GHashTable *user_routes;
87         GHashTable *setting_strings;
88
89         struct connman_ipaddress *ip;
90
91         GResolv *resolv;
92         guint resolv_id;
93 };
94
95 static int set_string(struct connman_provider *provider,
96                                         const char *key, const char *value)
97 {
98         struct connection_data *data;
99
100         data = connman_provider_get_data(provider);
101         if (data == NULL)
102                 return -EINVAL;
103
104         DBG("data %p provider %p key %s value %s", data, provider, key, value);
105
106         if (g_str_equal(key, "Type") == TRUE) {
107                 g_free(data->type);
108                 data->type = g_strdup(value);
109         } else if (g_str_equal(key, "Name") == TRUE) {
110                 g_free(data->name);
111                 data->name = g_strdup(value);
112         } else if (g_str_equal(key, "Host") == TRUE) {
113                 g_free(data->host);
114                 data->host = g_strdup(value);
115         } else if (g_str_equal(key, "VPN.Domain") == TRUE ||
116                                 g_str_equal(key, "Domain") == TRUE) {
117                 g_free(data->domain);
118                 data->domain = g_strdup(value);
119         } else
120                 g_hash_table_replace(data->setting_strings,
121                                 g_strdup(key), g_strdup(value));
122         return 0;
123 }
124
125 static const char *get_string(struct connman_provider *provider,
126                                                         const char *key)
127 {
128         struct connection_data *data;
129
130         data = connman_provider_get_data(provider);
131         if (data == NULL)
132                 return NULL;
133
134         DBG("data %p provider %p key %s", data, provider, key);
135
136         if (g_str_equal(key, "Type") == TRUE)
137                 return data->type;
138         else if (g_str_equal(key, "Name") == TRUE)
139                 return data->name;
140         else if (g_str_equal(key, "Host") == TRUE)
141                 return data->host;
142         else if (g_str_equal(key, "HostIP") == TRUE) {
143                 if (data->host_ip == NULL ||
144                                 data->host_ip[0] == NULL)
145                         return data->host;
146                 else
147                         return data->host_ip[0];
148         } else if (g_str_equal(key, "VPN.Domain") == TRUE)
149                 return data->domain;
150
151         return g_hash_table_lookup(data->setting_strings, key);
152 }
153
154 static char *get_ident(const char *path)
155 {
156         char *pos;
157
158         if (*path != '/')
159                 return NULL;
160
161         pos = strrchr(path, '/');
162         if (pos == NULL)
163                 return NULL;
164
165         return pos + 1;
166 }
167
168 static void cancel_host_resolv(struct connection_data *data)
169 {
170         if (data->resolv_id != 0)
171                 g_resolv_cancel_lookup(data->resolv, data->resolv_id);
172
173         data->resolv_id = 0;
174
175         g_resolv_unref(data->resolv);
176         data->resolv = NULL;
177 }
178
179 static gboolean remove_resolv(gpointer user_data)
180 {
181         struct connection_data *data = user_data;
182
183         cancel_host_resolv(data);
184
185         return FALSE;
186 }
187
188 static void resolv_result(GResolvResultStatus status,
189                                         char **results, gpointer user_data)
190 {
191         struct connection_data *data = user_data;
192
193         DBG("status %d", status);
194
195         if (status == G_RESOLV_RESULT_STATUS_SUCCESS && results != NULL &&
196                                                 g_strv_length(results) > 0)
197                 data->host_ip = g_strdupv(results);
198
199         /*
200          * We cannot unref the resolver here as resolv struct is manipulated
201          * by gresolv.c after we return from this callback.
202          */
203         g_timeout_add_seconds(0, remove_resolv, data);
204
205         data->resolv_id = 0;
206 }
207
208 static void resolv_host_addr(struct connection_data *data)
209 {
210         if (data->host == NULL)
211                 return;
212
213         if (connman_inet_check_ipaddress(data->host) > 0)
214                 return;
215
216         if (data->host_ip != NULL)
217                 return;
218
219         data->resolv = g_resolv_new(0);
220         if (data->resolv == NULL) {
221                 DBG("Cannot resolv %s", data->host);
222                 return;
223         }
224
225         DBG("Trying to resolv %s", data->host);
226
227         data->resolv_id = g_resolv_lookup_hostname(data->resolv, data->host,
228                                                 resolv_result, data);
229 }
230
231 static void free_config_cb_data(struct config_create_data *cb_data)
232 {
233         if (cb_data == NULL)
234                 return;
235
236         g_free(cb_data->path);
237         cb_data->path = NULL;
238
239         if (cb_data->message != NULL) {
240                 dbus_message_unref(cb_data->message);
241                 cb_data->message = NULL;
242         }
243
244         cb_data->callback = NULL;
245
246         g_free(cb_data);
247 }
248
249 static void set_provider_state(struct connection_data *data)
250 {
251         enum connman_provider_state state = CONNMAN_PROVIDER_STATE_UNKNOWN;
252         int err = 0;
253
254         if (g_str_equal(data->state, "ready") == TRUE) {
255                 state = CONNMAN_PROVIDER_STATE_READY;
256                 goto set;
257         } else if (g_str_equal(data->state, "configuration") == TRUE) {
258                 state = CONNMAN_PROVIDER_STATE_CONNECT;
259         } else if (g_str_equal(data->state, "idle") == TRUE) {
260                 state = CONNMAN_PROVIDER_STATE_IDLE;
261         } else if (g_str_equal(data->state, "disconnect") == TRUE) {
262                 err = ECONNREFUSED;
263                 state = CONNMAN_PROVIDER_STATE_DISCONNECT;
264                 goto set;
265         } else if (g_str_equal(data->state, "failure") == TRUE) {
266                 err = ECONNREFUSED;
267                 state = CONNMAN_PROVIDER_STATE_FAILURE;
268                 goto set;
269         }
270
271         connman_provider_set_state(data->provider, state);
272         return;
273
274 set:
275         if (data->cb_data != NULL)
276                 data->cb_data->callback(data->cb_data->message,
277                                         err, data->ident);
278
279         connman_provider_set_state(data->provider, state);
280
281         free_config_cb_data(data->cb_data);
282         data->cb_data = NULL;
283 }
284
285 static int create_provider(struct connection_data *data, void *user_data)
286 {
287         struct connman_provider_driver *driver = user_data;
288         int err;
289
290         DBG("%s", data->path);
291
292         data->provider = connman_provider_get(data->ident);
293         if (data->provider == NULL)
294                 return -ENOMEM;
295
296         DBG("provider %p name %s", data->provider, data->name);
297
298         connman_provider_set_data(data->provider, data);
299         connman_provider_set_driver(data->provider, driver);
300
301         err = connman_provider_create_service(data->provider);
302         if (err == 0) {
303                 if (g_str_equal(data->state, "ready") == TRUE) {
304                         connman_provider_set_index(data->provider,
305                                                         data->index);
306                         if (data->ip != NULL)
307                                 connman_provider_set_ipaddress(data->provider,
308                                                                 data->ip);
309                 }
310
311                 set_provider_state(data);
312         }
313
314         return 0;
315 }
316
317 static void destroy_route(gpointer user_data)
318 {
319         struct vpn_route *route = user_data;
320
321         g_free(route->network);
322         g_free(route->netmask);
323         g_free(route->gateway);
324         g_free(route);
325 }
326
327 static struct connection_data *create_connection_data(const char *path)
328 {
329         struct connection_data *data;
330
331         data = g_try_new0(struct connection_data, 1);
332         if (data == NULL)
333                 return NULL;
334
335         DBG("path %s", path);
336
337         data->path = g_strdup(path);
338         data->ident = g_strdup(get_ident(path));
339         data->index = -1;
340
341         data->setting_strings = g_hash_table_new_full(g_str_hash,
342                                                 g_str_equal, g_free, g_free);
343
344         data->server_routes = g_hash_table_new_full(g_direct_hash,
345                                         g_str_equal, g_free, destroy_route);
346         data->user_routes = g_hash_table_new_full(g_str_hash,
347                                         g_str_equal, g_free, destroy_route);
348
349         return data;
350 }
351
352 static int extract_ip(DBusMessageIter *array, int family,
353                                                 struct connection_data *data)
354 {
355         DBusMessageIter dict;
356         char *address = NULL, *gateway = NULL, *netmask = NULL, *peer = NULL;
357         unsigned char prefix_len;
358
359         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
360                 return -EINVAL;
361
362         dbus_message_iter_recurse(array, &dict);
363
364         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
365                 DBusMessageIter entry, value;
366                 const char *key;
367
368                 dbus_message_iter_recurse(&dict, &entry);
369                 dbus_message_iter_get_basic(&entry, &key);
370
371                 dbus_message_iter_next(&entry);
372                 dbus_message_iter_recurse(&entry, &value);
373
374                 if (g_str_equal(key, "Address") == TRUE) {
375                         dbus_message_iter_get_basic(&value, &address);
376                         DBG("address %s", address);
377                 } else if (g_str_equal(key, "Netmask") == TRUE) {
378                         dbus_message_iter_get_basic(&value, &netmask);
379                         DBG("netmask %s", netmask);
380                 } else if (g_str_equal(key, "PrefixLength") == TRUE) {
381                         dbus_message_iter_get_basic(&value, &netmask);
382                         DBG("prefix length %s", netmask);
383                 } else if (g_str_equal(key, "Peer") == TRUE) {
384                         dbus_message_iter_get_basic(&value, &peer);
385                         DBG("peer %s", peer);
386                 } else if (g_str_equal(key, "Gateway") == TRUE) {
387                         dbus_message_iter_get_basic(&value, &gateway);
388                         DBG("gateway %s", gateway);
389                 }
390
391                 dbus_message_iter_next(&dict);
392         }
393
394         data->ip = connman_ipaddress_alloc(family);
395         if (data->ip == NULL)
396                 return -ENOMEM;
397
398         switch (family) {
399         case AF_INET:
400                 connman_ipaddress_set_ipv4(data->ip, address, netmask,
401                                                                 gateway);
402                 break;
403         case AF_INET6:
404                 prefix_len = atoi(netmask);
405                 connman_ipaddress_set_ipv6(data->ip, address, prefix_len,
406                                                                 gateway);
407                 break;
408         default:
409                 return -EINVAL;
410         }
411
412         connman_ipaddress_set_peer(data->ip, peer);
413
414         return 0;
415 }
416
417 static int extract_nameservers(DBusMessageIter *array,
418                                                 struct connection_data *data)
419 {
420         DBusMessageIter entry;
421         char **nameservers = NULL;
422         int i = 0;
423
424         dbus_message_iter_recurse(array, &entry);
425
426         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
427                 const char *nameserver;
428
429                 dbus_message_iter_get_basic(&entry, &nameserver);
430
431                 nameservers = g_try_renew(char *, nameservers, i + 2);
432                 if (nameservers == NULL)
433                         return -ENOMEM;
434
435                 DBG("[%d] %s", i, nameserver);
436
437                 nameservers[i] = g_strdup(nameserver);
438                 if (nameservers[i] == NULL)
439                         return -ENOMEM;
440
441                 nameservers[++i] = NULL;
442
443                 dbus_message_iter_next(&entry);
444         }
445
446         g_strfreev(data->nameservers);
447         data->nameservers = nameservers;
448
449         return 0;
450 }
451
452 static int errorstr2val(const char *error) {
453         if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".InProgress") == 0)
454                 return -EINPROGRESS;
455
456         if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".AlreadyConnected") == 0)
457                 return -EISCONN;
458
459         return -ECONNREFUSED;
460 }
461
462 static void connect_reply(DBusPendingCall *call, void *user_data)
463 {
464         DBusMessage *reply;
465         DBusError error;
466         struct connection_data *data = user_data;
467         struct config_create_data *cb_data = data->cb_data;
468
469         if (dbus_pending_call_get_completed(call) == FALSE)
470                 return;
471
472         DBG("user_data %p path %s", user_data, cb_data ? cb_data->path : NULL);
473
474         reply = dbus_pending_call_steal_reply(call);
475
476         dbus_error_init(&error);
477
478         if (dbus_set_error_from_message(&error, reply) == TRUE) {
479                 int err = errorstr2val(error.name);
480                 if (err != -EINPROGRESS) {
481                         connman_error("Connect reply: %s (%s)", error.message,
482                                                                 error.name);
483                         dbus_error_free(&error);
484
485                         DBG("data %p cb_data %p", data, cb_data);
486                         if (cb_data != NULL) {
487                                 cb_data->callback(cb_data->message, err, NULL);
488                                 free_config_cb_data(cb_data);
489                                 data->cb_data = NULL;
490                         }
491                         goto done;
492                 }
493                 dbus_error_free(&error);
494         }
495
496         /*
497          * The vpn connection is up when we get a "ready" state
498          * property so at this point we do nothing for the provider
499          * state.
500          */
501
502 done:
503         dbus_message_unref(reply);
504
505         dbus_pending_call_unref(call);
506 }
507
508 static int connect_provider(struct connection_data *data, void *user_data)
509 {
510         DBusPendingCall *call;
511         DBusMessage *message;
512         struct config_create_data *cb_data = user_data;
513
514         DBG("data %p user %p path %s", data, cb_data, data->path);
515
516         message = dbus_message_new_method_call(VPN_SERVICE, data->path,
517                                         VPN_CONNECTION_INTERFACE,
518                                         VPN_CONNECT);
519         if (message == NULL)
520                 return -ENOMEM;
521
522         if (dbus_connection_send_with_reply(connection, message,
523                                         &call, DBUS_TIMEOUT) == FALSE) {
524                 connman_error("Unable to call %s.%s()",
525                         VPN_CONNECTION_INTERFACE, VPN_CONNECT);
526                 dbus_message_unref(message);
527                 return -EINVAL;
528         }
529
530         if (call == NULL) {
531                 dbus_message_unref(message);
532                 return -EINVAL;
533         }
534
535         if (cb_data != NULL) {
536                 g_free(cb_data->path);
537                 cb_data->path = g_strdup(data->path);
538         }
539
540         dbus_pending_call_set_notify(call, connect_reply, data, NULL);
541
542         dbus_message_unref(message);
543
544         return -EINPROGRESS;
545 }
546
547 static void add_connection(const char *path, DBusMessageIter *properties,
548                         void *user_data)
549 {
550         struct connection_data *data;
551         int err;
552         char *ident = get_ident(path);
553         connman_bool_t found = FALSE;
554
555         data = g_hash_table_lookup(vpn_connections, ident);
556         if (data != NULL) {
557                 /*
558                  * We might have a dummy connection struct here that
559                  * was created by configuration_create_reply() so in
560                  * that case just continue.
561                  */
562                 if (data->connect_pending == FALSE)
563                         return;
564
565                 found = TRUE;
566         } else {
567                 data = create_connection_data(path);
568                 if (data == NULL)
569                         return;
570         }
571
572         DBG("data %p path %s", data, path);
573
574         while (dbus_message_iter_get_arg_type(properties) ==
575                         DBUS_TYPE_DICT_ENTRY) {
576                 DBusMessageIter entry, value;
577                 const char *key;
578                 char *str;
579
580                 dbus_message_iter_recurse(properties, &entry);
581                 dbus_message_iter_get_basic(&entry, &key);
582
583                 dbus_message_iter_next(&entry);
584                 dbus_message_iter_recurse(&entry, &value);
585
586                 if (g_str_equal(key, "State") == TRUE) {
587                         dbus_message_iter_get_basic(&value, &str);
588                         DBG("state %s -> %s", data->state, str);
589                         data->state = g_strdup(str);
590                 } else if (g_str_equal(key, "IPv4") == TRUE) {
591                         extract_ip(&value, AF_INET, data);
592                 } else if (g_str_equal(key, "IPv6") == TRUE) {
593                         extract_ip(&value, AF_INET6, data);
594                 } else if (g_str_equal(key, "Name") == TRUE) {
595                         dbus_message_iter_get_basic(&value, &str);
596                         data->name = g_strdup(str);
597                 } else if (g_str_equal(key, "Type") == TRUE) {
598                         dbus_message_iter_get_basic(&value, &str);
599                         data->type = g_strdup(str);
600                 } else if (g_str_equal(key, "Host") == TRUE) {
601                         dbus_message_iter_get_basic(&value, &str);
602                         data->host = g_strdup(str);
603                 } else if (g_str_equal(key, "Domain") == TRUE) {
604                         dbus_message_iter_get_basic(&value, &str);
605                         data->domain = g_strdup(str);
606                 } else if (g_str_equal(key, "Nameservers") == TRUE) {
607                         extract_nameservers(&value, data);
608                 } else if (g_str_equal(key, "Index") == TRUE) {
609                         dbus_message_iter_get_basic(&value, &data->index);
610                 } else {
611                         if (dbus_message_iter_get_arg_type(&value) ==
612                                                         DBUS_TYPE_STRING) {
613                                 dbus_message_iter_get_basic(&value, &str);
614                                 g_hash_table_replace(data->setting_strings,
615                                                 g_strdup(key), g_strdup(str));
616                         } else {
617                                 DBG("unknown key %s", key);
618                         }
619                 }
620
621                 dbus_message_iter_next(properties);
622         }
623
624         if (found == FALSE)
625                 g_hash_table_insert(vpn_connections, g_strdup(data->ident),
626                                                                         data);
627
628         err = create_provider(data, user_data);
629         if (err < 0)
630                 goto out;
631
632         resolv_host_addr(data);
633
634         if (data->connect_pending == TRUE)
635                 connect_provider(data, data->cb_data);
636
637         return;
638
639 out:
640         DBG("removing %s", data->ident);
641         g_hash_table_remove(vpn_connections, data->ident);
642 }
643
644 static void get_connections_reply(DBusPendingCall *call, void *user_data)
645 {
646         DBusMessage *reply;
647         DBusError error;
648         DBusMessageIter array, dict;
649         const char *signature = DBUS_TYPE_ARRAY_AS_STRING
650                 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
651                 DBUS_TYPE_OBJECT_PATH_AS_STRING
652                 DBUS_TYPE_ARRAY_AS_STRING
653                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
654                 DBUS_TYPE_STRING_AS_STRING
655                 DBUS_TYPE_VARIANT_AS_STRING
656                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
657                 DBUS_STRUCT_END_CHAR_AS_STRING;
658
659         if (dbus_pending_call_get_completed(call) == FALSE)
660                 return;
661
662         DBG("");
663
664         reply = dbus_pending_call_steal_reply(call);
665
666         dbus_error_init(&error);
667
668         if (dbus_set_error_from_message(&error, reply) == TRUE) {
669                 connman_error("%s", error.message);
670                 dbus_error_free(&error);
671                 goto done;
672         }
673
674         if (dbus_message_has_signature(reply, signature) == FALSE) {
675                 connman_error("vpnd signature \"%s\" does not match "
676                                                         "expected \"%s\"",
677                         dbus_message_get_signature(reply), signature);
678                 goto done;
679         }
680
681         if (dbus_message_iter_init(reply, &array) == FALSE)
682                 goto done;
683
684         dbus_message_iter_recurse(&array, &dict);
685
686         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
687                 DBusMessageIter value, properties;
688                 const char *path;
689
690                 dbus_message_iter_recurse(&dict, &value);
691                 dbus_message_iter_get_basic(&value, &path);
692
693                 dbus_message_iter_next(&value);
694                 dbus_message_iter_recurse(&value, &properties);
695
696                 add_connection(path, &properties, user_data);
697
698                 dbus_message_iter_next(&dict);
699         }
700
701 done:
702         dbus_message_unref(reply);
703
704         dbus_pending_call_unref(call);
705 }
706
707 static int get_connections(void *user_data)
708 {
709         DBusPendingCall *call;
710         DBusMessage *message;
711
712         DBG("");
713
714         message = dbus_message_new_method_call(VPN_SERVICE, "/",
715                                         VPN_MANAGER_INTERFACE,
716                                         GET_CONNECTIONS);
717         if (message == NULL)
718                 return -ENOMEM;
719
720         if (dbus_connection_send_with_reply(connection, message,
721                                         &call, DBUS_TIMEOUT) == FALSE) {
722                 connman_error("Unable to call %s.%s()", VPN_MANAGER_INTERFACE,
723                                                         GET_CONNECTIONS);
724                 dbus_message_unref(message);
725                 return -EINVAL;
726         }
727
728         if (call == NULL) {
729                 dbus_message_unref(message);
730                 return -EINVAL;
731         }
732
733         dbus_pending_call_set_notify(call, get_connections_reply,
734                                                         user_data, NULL);
735
736         dbus_message_unref(message);
737
738         return -EINPROGRESS;
739 }
740
741 static int provider_probe(struct connman_provider *provider)
742 {
743         return 0;
744 }
745
746 static void remove_connection_reply(DBusPendingCall *call, void *user_data)
747 {
748         DBusMessage *reply;
749         DBusError error;
750
751         if (dbus_pending_call_get_completed(call) == FALSE)
752                 return;
753
754         DBG("");
755
756         reply = dbus_pending_call_steal_reply(call);
757
758         dbus_error_init(&error);
759
760         if (dbus_set_error_from_message(&error, reply) == TRUE) {
761                 /*
762                  * If the returned error is NotFound, it means that we
763                  * have actually removed the provider in vpnd already.
764                  */
765                 if (dbus_error_has_name(&error, CONNMAN_ERROR_INTERFACE
766                                                 ".NotFound") == FALSE)
767                         connman_error("%s", error.message);
768
769                 dbus_error_free(&error);
770         }
771
772         dbus_message_unref(reply);
773
774         dbus_pending_call_unref(call);
775 }
776
777 static int provider_remove(struct connman_provider *provider)
778 {
779         DBusPendingCall *call;
780         DBusMessage *message;
781         struct connection_data *data;
782
783         data = connman_provider_get_data(provider);
784
785         DBG("provider %p data %p", provider, data);
786
787         /*
788          * When provider.c:provider_remove() calls this function,
789          * it will remove the provider itself after the call.
790          * This means that we cannot use the provider pointer later
791          * as it is no longer valid.
792          */
793         data->provider = NULL;
794
795         message = dbus_message_new_method_call(VPN_SERVICE, "/",
796                                         VPN_MANAGER_INTERFACE,
797                                         VPN_REMOVE);
798         if (message == NULL)
799                 return -ENOMEM;
800
801         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &data->path,
802                                 NULL);
803
804         if (dbus_connection_send_with_reply(connection, message,
805                                         &call, DBUS_TIMEOUT) == FALSE) {
806                 connman_error("Unable to call %s.%s()", VPN_MANAGER_INTERFACE,
807                                                         VPN_REMOVE);
808                 dbus_message_unref(message);
809                 return -EINVAL;
810         }
811
812         if (call == NULL) {
813                 dbus_message_unref(message);
814                 return -EINVAL;
815         }
816
817         dbus_pending_call_set_notify(call, remove_connection_reply,
818                                                         NULL, NULL);
819
820         dbus_message_unref(message);
821
822         return 0;
823 }
824
825 static int provider_connect(struct connman_provider *provider)
826 {
827         struct connection_data *data;
828
829         data = connman_provider_get_data(provider);
830         if (data == NULL)
831                 return -EINVAL;
832
833         return connect_provider(data, NULL);
834 }
835
836 static void disconnect_reply(DBusPendingCall *call, void *user_data)
837 {
838         DBusMessage *reply;
839         DBusError error;
840
841         if (dbus_pending_call_get_completed(call) == FALSE)
842                 return;
843
844         DBG("user %p", user_data);
845
846         reply = dbus_pending_call_steal_reply(call);
847
848         dbus_error_init(&error);
849
850         if (dbus_set_error_from_message(&error, reply) == TRUE) {
851                 connman_error("%s", error.message);
852                 dbus_error_free(&error);
853                 goto done;
854         }
855
856 done:
857         dbus_message_unref(reply);
858
859         dbus_pending_call_unref(call);
860 }
861
862 static int disconnect_provider(struct connection_data *data)
863 {
864         DBusPendingCall *call;
865         DBusMessage *message;
866
867         DBG("data %p path %s", data, data->path);
868
869         message = dbus_message_new_method_call(VPN_SERVICE, data->path,
870                                         VPN_CONNECTION_INTERFACE,
871                                         VPN_DISCONNECT);
872         if (message == NULL)
873                 return -ENOMEM;
874
875         if (dbus_connection_send_with_reply(connection, message,
876                                         &call, DBUS_TIMEOUT) == FALSE) {
877                 connman_error("Unable to call %s.%s()",
878                         VPN_CONNECTION_INTERFACE, VPN_DISCONNECT);
879                 dbus_message_unref(message);
880                 return -EINVAL;
881         }
882
883         if (call == NULL) {
884                 dbus_message_unref(message);
885                 return -EINVAL;
886         }
887
888         dbus_pending_call_set_notify(call, disconnect_reply, NULL, NULL);
889
890         dbus_message_unref(message);
891
892         connman_provider_set_state(data->provider,
893                                         CONNMAN_PROVIDER_STATE_DISCONNECT);
894         /*
895          * We return 0 here instead of -EINPROGRESS because
896          * __connman_service_disconnect() needs to return something
897          * to gdbus so that gdbus will not call Disconnect() more
898          * than once. This way we do not need to pass the dbus reply
899          * message around the code.
900          */
901         return 0;
902 }
903
904 static int provider_disconnect(struct connman_provider *provider)
905 {
906         struct connection_data *data;
907
908         DBG("provider %p", provider);
909
910         data = connman_provider_get_data(provider);
911         if (data == NULL)
912                 return -EINVAL;
913
914         if (g_str_equal(data->state, "ready") == TRUE ||
915                         g_str_equal(data->state, "configuration") == TRUE)
916                 return disconnect_provider(data);
917
918         return 0;
919 }
920
921 static void configuration_create_reply(DBusPendingCall *call, void *user_data)
922 {
923         DBusMessage *reply;
924         DBusError error;
925         DBusMessageIter iter;
926         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
927         const char *path;
928         char *ident;
929         struct connection_data *data;
930         struct config_create_data *cb_data = user_data;
931
932         if (dbus_pending_call_get_completed(call) == FALSE)
933                 return;
934
935         DBG("user %p", cb_data);
936
937         reply = dbus_pending_call_steal_reply(call);
938
939         dbus_error_init(&error);
940
941         if (dbus_set_error_from_message(&error, reply) == TRUE) {
942                 connman_error("dbus error: %s", error.message);
943                 dbus_error_free(&error);
944                 goto done;
945         }
946
947         if (dbus_message_has_signature(reply, signature) == FALSE) {
948                 connman_error("vpn configuration signature \"%s\" does not "
949                                                 "match expected \"%s\"",
950                         dbus_message_get_signature(reply), signature);
951                 goto done;
952         }
953
954         if (dbus_message_iter_init(reply, &iter) == FALSE)
955                 goto done;
956
957         dbus_message_iter_get_basic(&iter, &path);
958
959         /*
960          * Then try to connect the VPN as expected by ConnectProvider API
961          */
962         ident = get_ident(path);
963
964         data = g_hash_table_lookup(vpn_connections, ident);
965         if (data == NULL) {
966                 /*
967                  * Someone removed the data. We cannot really continue.
968                  */
969                 DBG("Pending data not found for %s, cannot continue!", ident);
970         } else {
971                 data->call = NULL;
972                 data->connect_pending = TRUE;
973
974                 if (data->cb_data == NULL)
975                         data->cb_data = cb_data;
976                 else
977                         DBG("Connection callback data already in use!");
978
979                 /*
980                  * Connection is created in add_connections() after
981                  * we have received the ConnectionAdded signal.
982                  */
983
984                 DBG("cb %p msg %p", data->cb_data,
985                         data->cb_data ? data->cb_data->message : NULL);
986         }
987
988 done:
989         dbus_message_unref(reply);
990
991         dbus_pending_call_unref(call);
992 }
993
994 static void set_dbus_ident(char *ident)
995 {
996         int i, len = strlen(ident);
997
998         for (i = 0; i < len; i++) {
999                 if (ident[i] >= '0' && ident[i] <= '9')
1000                         continue;
1001                 if (ident[i] >= 'a' && ident[i] <= 'z')
1002                         continue;
1003                 if (ident[i] >= 'A' && ident[i] <= 'Z')
1004                         continue;
1005                 ident[i] = '_';
1006         }
1007 }
1008
1009 static struct vpn_route *parse_user_route(const char *user_route)
1010 {
1011         char *network, *netmask;
1012         struct vpn_route *route = NULL;
1013         int family = PF_UNSPEC;
1014         char **elems = g_strsplit(user_route, "/", 0);
1015
1016         if (elems == NULL)
1017                 return NULL;
1018
1019         network = elems[0];
1020         if (network == NULL || *network == '\0') {
1021                 DBG("no network/netmask set");
1022                 goto out;
1023         }
1024
1025         netmask = elems[1];
1026         if (netmask != NULL && *netmask == '\0') {
1027                 DBG("no netmask set");
1028                 goto out;
1029         }
1030
1031         if (g_strrstr(network, ":") != NULL)
1032                 family = AF_INET6;
1033         else if (g_strrstr(network, ".") != NULL) {
1034                 family = AF_INET;
1035
1036                 if (g_strrstr(netmask, ".") == NULL) {
1037                         /* We have netmask length */
1038                         in_addr_t addr;
1039                         struct in_addr netmask_in;
1040                         unsigned char prefix_len = 32;
1041
1042                         if (netmask != NULL) {
1043                                 char *ptr;
1044                                 long int value = strtol(netmask, &ptr, 10);
1045                                 if (ptr != netmask && *ptr == '\0' &&
1046                                                                 value <= 32)
1047                                         prefix_len = value;
1048                         }
1049
1050                         addr = 0xffffffff << (32 - prefix_len);
1051                         netmask_in.s_addr = htonl(addr);
1052                         netmask = inet_ntoa(netmask_in);
1053
1054                         DBG("network %s netmask %s", network, netmask);
1055                 }
1056         }
1057
1058         route = g_try_new(struct vpn_route, 1);
1059         if (route == NULL)
1060                 goto out;
1061
1062         route->network = g_strdup(network);
1063         route->netmask = g_strdup(netmask);
1064         route->gateway = NULL;
1065         route->family = family;
1066
1067 out:
1068         g_strfreev(elems);
1069         return route;
1070 }
1071
1072 static GSList *get_user_networks(DBusMessageIter *array)
1073 {
1074         DBusMessageIter entry;
1075         GSList *list = NULL;
1076
1077         dbus_message_iter_recurse(array, &entry);
1078
1079         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1080                 const char *val;
1081                 struct vpn_route *route;
1082
1083                 dbus_message_iter_get_basic(&entry, &val);
1084
1085                 route = parse_user_route(val);
1086                 if (route != NULL)
1087                         list = g_slist_prepend(list, route);
1088
1089                 dbus_message_iter_next(&entry);
1090         }
1091
1092         return list;
1093 }
1094
1095 static void append_route(DBusMessageIter *iter, void *user_data)
1096 {
1097         struct vpn_route *route = user_data;
1098         DBusMessageIter item;
1099         int family = 0;
1100
1101         connman_dbus_dict_open(iter, &item);
1102
1103         if (route == NULL)
1104                 goto empty_dict;
1105
1106         if (route->family == AF_INET)
1107                 family = 4;
1108         else if (route->family == AF_INET6)
1109                 family = 6;
1110
1111         if (family != 0)
1112                 connman_dbus_dict_append_basic(&item, "ProtocolFamily",
1113                                         DBUS_TYPE_INT32, &family);
1114
1115         if (route->network != NULL)
1116                 connman_dbus_dict_append_basic(&item, "Network",
1117                                         DBUS_TYPE_STRING, &route->network);
1118
1119         if (route->netmask != NULL)
1120                 connman_dbus_dict_append_basic(&item, "Netmask",
1121                                         DBUS_TYPE_STRING, &route->netmask);
1122
1123         if (route->gateway != NULL)
1124                 connman_dbus_dict_append_basic(&item, "Gateway",
1125                                         DBUS_TYPE_STRING, &route->gateway);
1126
1127 empty_dict:
1128         connman_dbus_dict_close(iter, &item);
1129 }
1130
1131 static void append_routes(DBusMessageIter *iter, void *user_data)
1132 {
1133         GSList *list, *routes = user_data;
1134
1135         DBG("routes %p", routes);
1136
1137         for (list = routes; list != NULL; list = g_slist_next(list)) {
1138                 DBusMessageIter dict;
1139                 struct vpn_route *route = list->data;
1140
1141                 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL,
1142                                                 &dict);
1143                 append_route(&dict, route);
1144                 dbus_message_iter_close_container(iter, &dict);
1145         }
1146 }
1147
1148 static int create_configuration(DBusMessage *msg, connection_ready_cb callback)
1149 {
1150         DBusMessage *new_msg = NULL;
1151         DBusPendingCall *call;
1152         DBusMessageIter iter, array, new_iter, new_dict;
1153         const char *type = NULL, *name = NULL;
1154         const char *host = NULL, *domain = NULL;
1155         char *ident, *me = NULL;
1156         int err = 0;
1157         dbus_bool_t result;
1158         struct connection_data *data;
1159         struct config_create_data *user_data = NULL;
1160         GSList *networks = NULL;
1161
1162         /*
1163          * We copy the old message data into new message. We cannot
1164          * just use the old message as is because the user route
1165          * information is not in the same format in vpnd.
1166          */
1167         new_msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
1168         dbus_message_iter_init_append(new_msg, &new_iter);
1169         connman_dbus_dict_open(&new_iter, &new_dict);
1170
1171         dbus_message_iter_init(msg, &iter);
1172         dbus_message_iter_recurse(&iter, &array);
1173
1174         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1175                 DBusMessageIter entry, value;
1176                 void *item_value;
1177                 const char *key;
1178                 int value_type;
1179
1180                 dbus_message_iter_recurse(&array, &entry);
1181                 dbus_message_iter_get_basic(&entry, &key);
1182
1183                 dbus_message_iter_next(&entry);
1184                 dbus_message_iter_recurse(&entry, &value);
1185
1186                 value_type = dbus_message_iter_get_arg_type(&value);
1187                 item_value = NULL;
1188
1189                 switch (value_type) {
1190                 case DBUS_TYPE_STRING:
1191                         dbus_message_iter_get_basic(&value, &item_value);
1192
1193                         if (g_str_equal(key, "Type") == TRUE) {
1194                                 type = (const char *)item_value;
1195                         } else if (g_str_equal(key, "Name") == TRUE) {
1196                                 name = (const char *)item_value;
1197                         } else if (g_str_equal(key, "Host") == TRUE) {
1198                                 host = (const char *)item_value;
1199                         } else if (g_str_equal(key, "VPN.Domain") == TRUE) {
1200                                 domain = (const char *)item_value;
1201                         }
1202
1203                         DBG("%s %s", key, (char *)item_value);
1204
1205                         if (item_value != NULL)
1206                                 connman_dbus_dict_append_basic(&new_dict, key,
1207                                                 value_type, &item_value);
1208                         break;
1209                 case DBUS_TYPE_ARRAY:
1210                         if (g_str_equal(key, "Networks") == TRUE) {
1211                                 networks = get_user_networks(&value);
1212                                 connman_dbus_dict_append_array(&new_dict,
1213                                                         "UserRoutes",
1214                                                         DBUS_TYPE_DICT_ENTRY,
1215                                                         append_routes,
1216                                                         networks);
1217                         }
1218                         break;
1219                 }
1220
1221                 dbus_message_iter_next(&array);
1222         }
1223
1224         connman_dbus_dict_close(&new_iter, &new_dict);
1225
1226         DBG("VPN type %s name %s host %s domain %s networks %p",
1227                 type, name, host, domain, networks);
1228
1229         if (host == NULL || domain == NULL) {
1230                 err = -EINVAL;
1231                 goto done;
1232         }
1233
1234         if (type == NULL || name == NULL) {
1235                 err = -EOPNOTSUPP;
1236                 goto done;
1237         }
1238
1239         ident = g_strdup_printf("%s_%s", host, domain);
1240         set_dbus_ident(ident);
1241
1242         DBG("ident %s", ident);
1243
1244         data = g_hash_table_lookup(vpn_connections, ident);
1245         if (data != NULL) {
1246                 if (data->call != NULL) {
1247                         connman_error("Dbus call already pending");
1248                         err = -EINPROGRESS;
1249                         goto done;
1250                 }
1251         } else {
1252                 char *path = g_strdup_printf("%s/connection/%s", VPN_PATH,
1253                                                                 ident);
1254                 data = create_connection_data(path);
1255                 g_free(path);
1256
1257                 if (data == NULL) {
1258                         err = -ENOMEM;
1259                         goto done;
1260                 }
1261
1262                 g_hash_table_insert(vpn_connections, g_strdup(ident), data);
1263         }
1264
1265         /*
1266          * User called net.connman.Manager.ConnectProvider if we are here.
1267          * So use the data from original message in the new msg.
1268          */
1269         me = g_strdup(dbus_message_get_destination(msg));
1270
1271         dbus_message_set_interface(new_msg, VPN_MANAGER_INTERFACE);
1272         dbus_message_set_path(new_msg, "/");
1273         dbus_message_set_destination(new_msg, VPN_SERVICE);
1274         dbus_message_set_sender(new_msg, me);
1275         dbus_message_set_member(new_msg, "Create");
1276
1277         result = dbus_connection_send_with_reply(connection, new_msg,
1278                                                 &call, DBUS_TIMEOUT);
1279         if (result == FALSE || call == NULL) {
1280                 err = -EIO;
1281                 goto done;
1282         }
1283
1284         if (data->cb_data == NULL) {
1285                 user_data = g_try_new(struct config_create_data, 1);
1286                 if (user_data != NULL) {
1287                         user_data->callback = callback;
1288                         user_data->message = dbus_message_ref(msg);
1289                         user_data->path = NULL;
1290
1291                         DBG("cb %p msg %p", user_data, msg);
1292                 }
1293         } else {
1294                 DBG("Configuration callback data already pending, "
1295                         "discarding new data.");
1296         }
1297
1298         dbus_pending_call_set_notify(call, configuration_create_reply,
1299                                                         user_data, NULL);
1300         data->call = call;
1301
1302 done:
1303         if (new_msg != NULL)
1304                 dbus_message_unref(new_msg);
1305
1306         if (networks != NULL)
1307                 g_slist_free_full(networks, destroy_route);
1308
1309         g_free(me);
1310         return err;
1311 }
1312
1313 static connman_bool_t check_host(char **hosts, char *host)
1314 {
1315         int i;
1316
1317         if (hosts == NULL)
1318                 return FALSE;
1319
1320         for (i = 0; hosts[i] != NULL; i++) {
1321                 if (g_strcmp0(hosts[i], host) == 0)
1322                         return TRUE;
1323         }
1324
1325         return FALSE;
1326 }
1327
1328 static void set_route(struct connection_data *data, struct vpn_route *route)
1329 {
1330         /*
1331          * If the VPN administrator/user has given a route to
1332          * VPN server, then we must discard that because the
1333          * server cannot be contacted via VPN tunnel.
1334          */
1335         if (check_host(data->host_ip, route->network) == TRUE) {
1336                 DBG("Discarding VPN route to %s via %s at index %d",
1337                         route->network, route->gateway, data->index);
1338                 return;
1339         }
1340
1341         if (route->family == AF_INET6) {
1342                 unsigned char prefix_len = atoi(route->netmask);
1343
1344                 connman_inet_add_ipv6_network_route(data->index,
1345                                                         route->network,
1346                                                         route->gateway,
1347                                                         prefix_len);
1348         } else {
1349                 connman_inet_add_network_route(data->index, route->network,
1350                                                 route->gateway,
1351                                                 route->netmask);
1352         }
1353 }
1354
1355 static int set_routes(struct connman_provider *provider,
1356                                 enum connman_provider_route_type type)
1357 {
1358         struct connection_data *data;
1359         GHashTableIter iter;
1360         gpointer value, key;
1361
1362         DBG("provider %p", provider);
1363
1364         data = connman_provider_get_data(provider);
1365         if (data == NULL)
1366                 return -EINVAL;
1367
1368         if (type == CONNMAN_PROVIDER_ROUTE_ALL ||
1369                                         type == CONNMAN_PROVIDER_ROUTE_USER) {
1370                 g_hash_table_iter_init(&iter, data->user_routes);
1371
1372                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE)
1373                         set_route(data, value);
1374         }
1375
1376         if (type == CONNMAN_PROVIDER_ROUTE_ALL ||
1377                                 type == CONNMAN_PROVIDER_ROUTE_SERVER) {
1378                 g_hash_table_iter_init(&iter, data->server_routes);
1379
1380                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE)
1381                         set_route(data, value);
1382         }
1383
1384         return 0;
1385 }
1386
1387 static connman_bool_t check_routes(struct connman_provider *provider)
1388 {
1389         struct connection_data *data;
1390
1391         DBG("provider %p", provider);
1392
1393         data = connman_provider_get_data(provider);
1394         if (data == NULL)
1395                 return FALSE;
1396
1397         if (data->user_routes != NULL &&
1398                         g_hash_table_size(data->user_routes) > 0)
1399                 return TRUE;
1400
1401         if (data->server_routes != NULL &&
1402                         g_hash_table_size(data->server_routes) > 0)
1403                 return TRUE;
1404
1405         return FALSE;
1406 }
1407
1408 static struct connman_provider_driver provider_driver = {
1409         .name = "VPN",
1410         .type = CONNMAN_PROVIDER_TYPE_VPN,
1411         .probe = provider_probe,
1412         .remove = provider_remove,
1413         .connect = provider_connect,
1414         .disconnect = provider_disconnect,
1415         .set_property = set_string,
1416         .get_property = get_string,
1417         .create = create_configuration,
1418         .set_routes = set_routes,
1419         .check_routes = check_routes,
1420 };
1421
1422 static void destroy_provider(struct connection_data *data)
1423 {
1424         DBG("data %p", data);
1425
1426         if (g_str_equal(data->state, "ready") == TRUE ||
1427                         g_str_equal(data->state, "configuration") == TRUE)
1428                 connman_provider_disconnect(data->provider);
1429
1430         if (data->call != NULL)
1431                 dbus_pending_call_cancel(data->call);
1432
1433         connman_provider_put(data->provider);
1434
1435         data->provider = NULL;
1436 }
1437
1438 static void connection_destroy(gpointer hash_data)
1439 {
1440         struct connection_data *data = hash_data;
1441
1442         DBG("data %p", data);
1443
1444         if (data->provider != NULL)
1445                 destroy_provider(data);
1446
1447         g_free(data->path);
1448         g_free(data->ident);
1449         g_free(data->state);
1450         g_free(data->type);
1451         g_free(data->name);
1452         g_free(data->host);
1453         g_free(data->domain);
1454         g_hash_table_destroy(data->server_routes);
1455         g_hash_table_destroy(data->user_routes);
1456         g_strfreev(data->nameservers);
1457         g_hash_table_destroy(data->setting_strings);
1458         connman_ipaddress_free(data->ip);
1459
1460         cancel_host_resolv(data);
1461
1462         g_free(data);
1463 }
1464
1465 static void vpnd_created(DBusConnection *conn, void *user_data)
1466 {
1467         DBG("connection %p", conn);
1468
1469         get_connections(user_data);
1470 }
1471
1472 static void vpnd_removed(DBusConnection *conn, void *user_data)
1473 {
1474         DBG("connection %p", conn);
1475
1476         g_hash_table_remove_all(vpn_connections);
1477 }
1478
1479 static void remove_connection(DBusConnection *conn, const char *path)
1480 {
1481         DBG("path %s", path);
1482
1483         g_hash_table_remove(vpn_connections, get_ident(path));
1484 }
1485
1486 static gboolean connection_removed(DBusConnection *conn, DBusMessage *message,
1487                                 void *user_data)
1488 {
1489         const char *path;
1490         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
1491
1492         if (dbus_message_has_signature(message, signature) == FALSE) {
1493                 connman_error("vpn removed signature \"%s\" does not match "
1494                                                         "expected \"%s\"",
1495                         dbus_message_get_signature(message), signature);
1496                 return TRUE;
1497         }
1498
1499         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
1500                                 DBUS_TYPE_INVALID);
1501         remove_connection(conn, path);
1502         return TRUE;
1503 }
1504
1505 static gboolean connection_added(DBusConnection *conn, DBusMessage *message,
1506                                 void *user_data)
1507 {
1508         DBusMessageIter iter, properties;
1509         const char *path;
1510         const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
1511                 DBUS_TYPE_ARRAY_AS_STRING
1512                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1513                 DBUS_TYPE_STRING_AS_STRING
1514                 DBUS_TYPE_VARIANT_AS_STRING
1515                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
1516
1517         if (dbus_message_has_signature(message, signature) == FALSE) {
1518                 connman_error("vpn ConnectionAdded signature \"%s\" does not "
1519                                                 "match expected \"%s\"",
1520                         dbus_message_get_signature(message), signature);
1521                 return TRUE;
1522         }
1523
1524         DBG("");
1525
1526         if (dbus_message_iter_init(message, &iter) == FALSE)
1527                 return TRUE;
1528
1529         dbus_message_iter_get_basic(&iter, &path);
1530
1531         dbus_message_iter_next(&iter);
1532         dbus_message_iter_recurse(&iter, &properties);
1533
1534         add_connection(path, &properties, user_data);
1535
1536         return TRUE;
1537 }
1538
1539 static int save_route(GHashTable *routes, int family, const char *network,
1540                         const char *netmask, const char *gateway)
1541 {
1542         struct vpn_route *route;
1543         char *key = g_strdup_printf("%d/%s/%s", family, network, netmask);
1544
1545         DBG("family %d network %s netmask %s", family, network, netmask);
1546
1547         route = g_hash_table_lookup(routes, key);
1548         if (route == NULL) {
1549                 route = g_try_new0(struct vpn_route, 1);
1550                 if (route == NULL) {
1551                         connman_error("out of memory");
1552                         return -ENOMEM;
1553                 }
1554
1555                 route->family = family;
1556                 route->network = g_strdup(network);
1557                 route->netmask = g_strdup(netmask);
1558                 route->gateway = g_strdup(gateway);
1559
1560                 g_hash_table_replace(routes, key, route);
1561         } else
1562                 g_free(key);
1563
1564         return 0;
1565 }
1566
1567 static int read_route_dict(GHashTable *routes, DBusMessageIter *dicts)
1568 {
1569         DBusMessageIter dict;
1570         const char *network, *netmask, *gateway;
1571         int family;
1572
1573         dbus_message_iter_recurse(dicts, &dict);
1574
1575         network = netmask = gateway = NULL;
1576         family = PF_UNSPEC;
1577
1578         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1579
1580                 DBusMessageIter entry, value;
1581                 const char *key;
1582
1583                 dbus_message_iter_recurse(&dict, &entry);
1584                 dbus_message_iter_get_basic(&entry, &key);
1585
1586                 dbus_message_iter_next(&entry);
1587                 dbus_message_iter_recurse(&entry, &value);
1588
1589                 if (g_str_equal(key, "ProtocolFamily") == TRUE) {
1590                         int pf;
1591                         dbus_message_iter_get_basic(&value, &pf);
1592                         switch (pf) {
1593                         case 4:
1594                                 family = AF_INET;
1595                                 break;
1596                         case 6:
1597                                 family = AF_INET6;
1598                                 break;
1599                         }
1600                         DBG("family %d", family);
1601                 } else if (g_str_equal(key, "Netmask") == TRUE) {
1602                         dbus_message_iter_get_basic(&value, &netmask);
1603                         DBG("netmask %s", netmask);
1604                 } else if (g_str_equal(key, "Network") == TRUE) {
1605                         dbus_message_iter_get_basic(&value, &network);
1606                         DBG("host %s", network);
1607                 } else if (g_str_equal(key, "Gateway") == TRUE) {
1608                         dbus_message_iter_get_basic(&value, &gateway);
1609                         DBG("gateway %s", gateway);
1610                 }
1611
1612                 dbus_message_iter_next(&dict);
1613         }
1614
1615         if (netmask == NULL || network == NULL || gateway == NULL) {
1616                 DBG("Value missing.");
1617                 return -EINVAL;
1618         }
1619
1620         return save_route(routes, family, network, netmask, gateway);
1621 }
1622
1623 static int routes_changed(DBusMessageIter *array, GHashTable *routes)
1624 {
1625         DBusMessageIter entry;
1626         int ret = -EINVAL;
1627
1628         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) {
1629                 DBG("Expecting array, ignoring routes.");
1630                 return -EINVAL;
1631         }
1632
1633         while (dbus_message_iter_get_arg_type(array) == DBUS_TYPE_ARRAY) {
1634
1635                 dbus_message_iter_recurse(array, &entry);
1636
1637                 while (dbus_message_iter_get_arg_type(&entry) ==
1638                                                         DBUS_TYPE_STRUCT) {
1639                         DBusMessageIter dicts;
1640
1641                         dbus_message_iter_recurse(&entry, &dicts);
1642
1643                         while (dbus_message_iter_get_arg_type(&dicts) ==
1644                                                         DBUS_TYPE_ARRAY) {
1645                                 int err = read_route_dict(routes, &dicts);
1646                                 if (ret != 0)
1647                                         ret = err;
1648                                 dbus_message_iter_next(&dicts);
1649                         }
1650
1651                         dbus_message_iter_next(&entry);
1652                 }
1653
1654                 dbus_message_iter_next(array);
1655         }
1656
1657         return ret;
1658 }
1659
1660 static gboolean property_changed(DBusConnection *conn,
1661                                 DBusMessage *message,
1662                                 void *user_data)
1663 {
1664         const char *path = dbus_message_get_path(message);
1665         struct connection_data *data = NULL;
1666         DBusMessageIter iter, value;
1667         connman_bool_t ip_set = FALSE;
1668         int err;
1669         char *str;
1670         const char *key;
1671         const char *signature = DBUS_TYPE_STRING_AS_STRING
1672                 DBUS_TYPE_VARIANT_AS_STRING;
1673
1674         if (dbus_message_has_signature(message, signature) == FALSE) {
1675                 connman_error("vpn property signature \"%s\" does not match "
1676                                                         "expected \"%s\"",
1677                         dbus_message_get_signature(message), signature);
1678                 return TRUE;
1679         }
1680
1681         data = g_hash_table_lookup(vpn_connections, get_ident(path));
1682         if (data == NULL)
1683                 return TRUE;
1684
1685         if (dbus_message_iter_init(message, &iter) == FALSE)
1686                 return TRUE;
1687
1688         dbus_message_iter_get_basic(&iter, &key);
1689
1690         dbus_message_iter_next(&iter);
1691         dbus_message_iter_recurse(&iter, &value);
1692
1693         DBG("key %s", key);
1694
1695         if (g_str_equal(key, "State") == TRUE) {
1696                 dbus_message_iter_get_basic(&value, &str);
1697
1698                 DBG("%s %s -> %s", data->path, data->state, str);
1699
1700                 if (g_str_equal(data->state, str) == TRUE)
1701                         return TRUE;
1702
1703                 g_free(data->state);
1704                 data->state = g_strdup(str);
1705
1706                 set_provider_state(data);
1707         } else if (g_str_equal(key, "Index") == TRUE) {
1708                 dbus_message_iter_get_basic(&value, &data->index);
1709                 connman_provider_set_index(data->provider, data->index);
1710         } else if (g_str_equal(key, "IPv4") == TRUE) {
1711                 err = extract_ip(&value, AF_INET, data);
1712                 ip_set = TRUE;
1713         } else if (g_str_equal(key, "IPv6") == TRUE) {
1714                 err = extract_ip(&value, AF_INET6, data);
1715                 ip_set = TRUE;
1716         } else if (g_str_equal(key, "ServerRoutes") == TRUE) {
1717                 err = routes_changed(&value, data->server_routes);
1718                 /*
1719                  * Note that the vpnd will delay the route sending a bit
1720                  * (in order to collect the routes from VPN client),
1721                  * so we might have got the State changed property before
1722                  * we got ServerRoutes. This means that we must try to set
1723                  * the routes here because they would be left unset otherwise.
1724                  */
1725                 if (err == 0)
1726                         set_routes(data->provider,
1727                                                 CONNMAN_PROVIDER_ROUTE_SERVER);
1728         } else if (g_str_equal(key, "UserRoutes") == TRUE) {
1729                 err = routes_changed(&value, data->user_routes);
1730                 if (err == 0)
1731                         set_routes(data->provider,
1732                                                 CONNMAN_PROVIDER_ROUTE_USER);
1733         } else if (g_str_equal(key, "Nameservers") == TRUE) {
1734                 extract_nameservers(&value, data);
1735         }
1736
1737         if (ip_set == TRUE && err == 0) {
1738                 err = connman_provider_set_ipaddress(data->provider, data->ip);
1739                 if (err < 0)
1740                         DBG("setting provider IP address failed (%s/%d)",
1741                                 strerror(-err), -err);
1742         }
1743
1744         return TRUE;
1745 }
1746
1747 static int vpn_init(void)
1748 {
1749         int err;
1750
1751         connection = connman_dbus_get_connection();
1752         if (connection == NULL)
1753                 return -EIO;
1754
1755         watch = g_dbus_add_service_watch(connection, VPN_SERVICE,
1756                         vpnd_created, vpnd_removed, &provider_driver, NULL);
1757
1758         added_watch = g_dbus_add_signal_watch(connection, VPN_SERVICE, NULL,
1759                                         VPN_MANAGER_INTERFACE,
1760                                         CONNECTION_ADDED, connection_added,
1761                                         &provider_driver, NULL);
1762
1763         removed_watch = g_dbus_add_signal_watch(connection, VPN_SERVICE, NULL,
1764                                         VPN_MANAGER_INTERFACE,
1765                                         CONNECTION_REMOVED, connection_removed,
1766                                         NULL, NULL);
1767
1768         property_watch = g_dbus_add_signal_watch(connection, VPN_SERVICE, NULL,
1769                                         VPN_CONNECTION_INTERFACE,
1770                                         PROPERTY_CHANGED, property_changed,
1771                                         NULL, NULL);
1772
1773         if (added_watch == 0 || removed_watch == 0 || property_watch == 0) {
1774                 err = -EIO;
1775                 goto remove;
1776         }
1777
1778         err = connman_provider_driver_register(&provider_driver);
1779         if (err == 0) {
1780                 vpn_connections = g_hash_table_new_full(g_str_hash,
1781                                                 g_str_equal,
1782                                                 g_free, connection_destroy);
1783
1784                 vpnd_created(connection, &provider_driver);
1785         }
1786
1787         return err;
1788
1789 remove:
1790         g_dbus_remove_watch(connection, watch);
1791         g_dbus_remove_watch(connection, added_watch);
1792         g_dbus_remove_watch(connection, removed_watch);
1793         g_dbus_remove_watch(connection, property_watch);
1794
1795         dbus_connection_unref(connection);
1796
1797         return err;
1798 }
1799
1800 static void vpn_exit(void)
1801 {
1802         g_dbus_remove_watch(connection, watch);
1803         g_dbus_remove_watch(connection, added_watch);
1804         g_dbus_remove_watch(connection, removed_watch);
1805         g_dbus_remove_watch(connection, property_watch);
1806
1807         connman_provider_driver_unregister(&provider_driver);
1808
1809         if (vpn_connections != NULL)
1810                 g_hash_table_destroy(vpn_connections);
1811
1812         dbus_connection_unref(connection);
1813 }
1814
1815 CONNMAN_PLUGIN_DEFINE(vpn, "VPN plugin", VERSION,
1816                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, vpn_init, vpn_exit)