e04670c85d13b5a0a093e97ee35b007e637c533c
[platform/upstream/connman.git] / vpn / plugins / vpn.c
1 /*
2  *
3  *  ConnMan VPN daemon
4  *
5  *  Copyright (C) 2007-2013  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 <fcntl.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
34 #include <linux/if_tun.h>
35 #include <net/if.h>
36 #include <sys/types.h>
37 #include <pwd.h>
38 #include <grp.h>
39
40 #include <dbus/dbus.h>
41
42 #include <glib/gprintf.h>
43
44 #include <connman/log.h>
45 #include <connman/rtnl.h>
46 #include <connman/task.h>
47 #include <connman/inet.h>
48
49 #include "../vpn-rtnl.h"
50 #include "../vpn-provider.h"
51
52 #include "vpn.h"
53 #include "../vpn.h"
54
55 struct vpn_data {
56         struct vpn_provider *provider;
57         char *if_name;
58         unsigned flags;
59         unsigned int watch;
60         enum vpn_state state;
61         struct connman_task *task;
62         int tun_flags;
63 };
64
65 struct vpn_driver_data {
66         const char *name;
67         const char *program;
68         struct vpn_driver *vpn_driver;
69         struct vpn_provider_driver provider_driver;
70 };
71
72 GHashTable *driver_hash = NULL;
73
74 static int stop_vpn(struct vpn_provider *provider)
75 {
76         struct vpn_data *data = vpn_provider_get_data(provider);
77         struct vpn_driver_data *vpn_driver_data;
78         const char *name;
79         struct ifreq ifr;
80         int fd, err;
81
82         if (!data)
83                 return -EINVAL;
84
85         name = vpn_provider_get_driver_name(provider);
86         if (!name)
87                 return -EINVAL;
88
89         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
90
91         if (vpn_driver_data && vpn_driver_data->vpn_driver &&
92                         vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_TUN) {
93                 vpn_driver_data->vpn_driver->disconnect(data->provider);
94                 return 0;
95         }
96
97         memset(&ifr, 0, sizeof(ifr));
98         ifr.ifr_flags = data->tun_flags | IFF_NO_PI;
99         sprintf(ifr.ifr_name, "%s", data->if_name);
100
101         fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
102         if (fd < 0) {
103                 err = -errno;
104                 connman_error("Failed to open /dev/net/tun to device %s: %s",
105                               data->if_name, strerror(errno));
106                 return err;
107         }
108
109         if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
110                 err = -errno;
111                 connman_error("Failed to TUNSETIFF for device %s to it: %s",
112                               data->if_name, strerror(errno));
113                 close(fd);
114                 return err;
115         }
116
117         if (ioctl(fd, TUNSETPERSIST, 0)) {
118                 err = -errno;
119                 connman_error("Failed to set tun device %s nonpersistent: %s",
120                               data->if_name, strerror(errno));
121                 close(fd);
122                 return err;
123         }
124         close(fd);
125         DBG("Killed tun device %s", data->if_name);
126         return 0;
127 }
128
129 void vpn_died(struct connman_task *task, int exit_code, void *user_data)
130 {
131         struct vpn_provider *provider = user_data;
132         struct vpn_data *data = vpn_provider_get_data(provider);
133         int state = VPN_STATE_FAILURE;
134         enum vpn_provider_error ret;
135
136         DBG("provider %p data %p", provider, data);
137
138         if (!data)
139                 goto vpn_exit;
140
141         /* The task may die after we have already started the new one */
142         if (data->task != task)
143                 goto done;
144
145         state = data->state;
146
147         stop_vpn(provider);
148         vpn_provider_set_data(provider, NULL);
149
150         if (data->watch != 0) {
151                 vpn_rtnl_remove_watch(data->watch);
152                 data->watch = 0;
153                 vpn_provider_unref(provider);
154         }
155
156 vpn_exit:
157         if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) {
158                 const char *name;
159                 struct vpn_driver_data *vpn_data = NULL;
160
161                 name = vpn_provider_get_driver_name(provider);
162                 if (name)
163                         vpn_data = g_hash_table_lookup(driver_hash, name);
164
165                 if (vpn_data &&
166                                 vpn_data->vpn_driver->error_code)
167                         ret = vpn_data->vpn_driver->error_code(provider,
168                                         exit_code);
169                 else
170                         ret = VPN_PROVIDER_ERROR_UNKNOWN;
171
172                 vpn_provider_indicate_error(provider, ret);
173         } else
174                 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
175
176         vpn_provider_set_index(provider, -1);
177
178         if (data) {
179                 vpn_provider_unref(data->provider);
180                 g_free(data->if_name);
181                 g_free(data);
182         }
183
184 done:
185         connman_task_destroy(task);
186 }
187
188 int vpn_set_ifname(struct vpn_provider *provider, const char *ifname)
189 {
190         struct vpn_data *data = vpn_provider_get_data(provider);
191         int index;
192
193         if (!ifname || !data)
194                 return  -EIO;
195
196         index = connman_inet_ifindex(ifname);
197         if (index < 0)
198                 return  -EIO;
199
200         if (data->if_name)
201                 g_free(data->if_name);
202
203         data->if_name = (char *)g_strdup(ifname);
204         vpn_provider_set_index(provider, index);
205
206         return 0;
207 }
208
209 static int vpn_set_state(struct vpn_provider *provider,
210                                                 enum vpn_provider_state state)
211 {
212         struct vpn_data *data = vpn_provider_get_data(provider);
213         if (!data)
214                 return -EINVAL;
215
216         switch (state) {
217         case VPN_PROVIDER_STATE_UNKNOWN:
218                 return -EINVAL;
219         case VPN_PROVIDER_STATE_IDLE:
220                 data->state = VPN_STATE_IDLE;
221                 break;
222         case VPN_PROVIDER_STATE_CONNECT:
223         case VPN_PROVIDER_STATE_READY:
224                 data->state = VPN_STATE_CONNECT;
225                 break;
226         case VPN_PROVIDER_STATE_DISCONNECT:
227                 data->state = VPN_STATE_DISCONNECT;
228                 break;
229         case VPN_PROVIDER_STATE_FAILURE:
230                 data->state = VPN_STATE_FAILURE;
231                 break;
232         }
233
234         return 0;
235 }
236
237 static void vpn_newlink(unsigned flags, unsigned change, void *user_data)
238 {
239         struct vpn_provider *provider = user_data;
240         struct vpn_data *data = vpn_provider_get_data(provider);
241
242         if ((data->flags & IFF_UP) != (flags & IFF_UP)) {
243                 if (flags & IFF_UP) {
244                         data->state = VPN_STATE_READY;
245                         vpn_provider_set_state(provider,
246                                         VPN_PROVIDER_STATE_READY);
247                 }
248         }
249         data->flags = flags;
250 }
251
252 static DBusMessage *vpn_notify(struct connman_task *task,
253                         DBusMessage *msg, void *user_data)
254 {
255         struct vpn_provider *provider = user_data;
256         struct vpn_data *data;
257         struct vpn_driver_data *vpn_driver_data;
258         const char *name;
259         int state, index, err;
260
261         data = vpn_provider_get_data(provider);
262
263         name = vpn_provider_get_driver_name(provider);
264
265         if (!name) {
266                 DBG("Cannot find VPN driver for provider %p", provider);
267                 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
268                 return NULL;
269         }
270
271         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
272         if (!vpn_driver_data) {
273                 DBG("Cannot find VPN driver data for name %s", name);
274                 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE);
275                 return NULL;
276         }
277
278         state = vpn_driver_data->vpn_driver->notify(msg, provider);
279
280         DBG("provider %p driver %s state %d", provider, name, state);
281
282         switch (state) {
283         case VPN_STATE_CONNECT:
284         case VPN_STATE_READY:
285                 if (data->state == VPN_STATE_READY) {
286                         /*
287                          * This is the restart case, in which case we must
288                          * just set the IP address.
289                          *
290                          * We need to remove first the old address, just
291                          * replacing the old address will not work as expected
292                          * because the old address will linger in the interface
293                          * and not disappear so the clearing is needed here.
294                          *
295                          * Also the state must change, otherwise the routes
296                          * will not be set properly.
297                          */
298                         vpn_provider_set_state(provider,
299                                                 VPN_PROVIDER_STATE_CONNECT);
300
301                         vpn_provider_clear_address(provider, AF_INET);
302                         vpn_provider_clear_address(provider, AF_INET6);
303
304                         vpn_provider_change_address(provider);
305                         vpn_provider_set_state(provider,
306                                                 VPN_PROVIDER_STATE_READY);
307                         break;
308                 }
309
310                 index = vpn_provider_get_index(provider);
311                 vpn_provider_ref(provider);
312                 data->watch = vpn_rtnl_add_newlink_watch(index,
313                                                      vpn_newlink, provider);
314                 err = connman_inet_ifup(index);
315                 if (err < 0) {
316                         if (err == -EALREADY) {
317                                 /*
318                                  * So the interface is up already, that is just
319                                  * great. Unfortunately in this case the
320                                  * newlink watch might not have been called at
321                                  * all. We must manually call it here so that
322                                  * the provider can go to ready state and the
323                                  * routes are setup properly. Also reset flags
324                                  * so vpn_newlink() can handle the change.
325                                  */
326                                 data->flags = 0;
327                                 vpn_newlink(IFF_UP, 0, provider);
328                         } else {
329                                 DBG("Cannot take interface %d up err %d/%s",
330                                         index, -err, strerror(-err));
331                         }
332                 }
333                 break;
334
335         case VPN_STATE_UNKNOWN:
336         case VPN_STATE_IDLE:
337         case VPN_STATE_DISCONNECT:
338         case VPN_STATE_FAILURE:
339                 vpn_provider_set_state(provider,
340                                         VPN_PROVIDER_STATE_DISCONNECT);
341                 break;
342
343         case VPN_STATE_AUTH_FAILURE:
344                 vpn_provider_indicate_error(provider,
345                                         VPN_PROVIDER_ERROR_AUTH_FAILED);
346                 break;
347         }
348
349         return NULL;
350 }
351
352 static int vpn_create_tun(struct vpn_provider *provider, int flags)
353 {
354         struct vpn_data *data = vpn_provider_get_data(provider);
355         struct ifreq ifr;
356         int i, fd, index;
357         int ret = 0;
358
359         if (!data)
360                 return -EISCONN;
361
362         fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
363         if (fd < 0) {
364                 i = -errno;
365                 connman_error("Failed to open /dev/net/tun: %s",
366                               strerror(errno));
367                 ret = i;
368                 goto exist_err;
369         }
370
371         memset(&ifr, 0, sizeof(ifr));
372         ifr.ifr_flags = flags | IFF_NO_PI;
373
374         for (i = 0; i < 256; i++) {
375                 sprintf(ifr.ifr_name, "vpn%d", i);
376
377                 if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
378                         break;
379         }
380
381         if (i == 256) {
382                 connman_error("Failed to find available tun device");
383                 close(fd);
384                 ret = -ENODEV;
385                 goto exist_err;
386         }
387
388         data->tun_flags = flags;
389         g_free(data->if_name);
390         data->if_name = (char *)g_strdup(ifr.ifr_name);
391         if (!data->if_name) {
392                 connman_error("Failed to allocate memory");
393                 close(fd);
394                 ret = -ENOMEM;
395                 goto exist_err;
396         }
397
398         if (ioctl(fd, TUNSETPERSIST, 1)) {
399                 i = -errno;
400                 connman_error("Failed to set tun persistent: %s",
401                               strerror(errno));
402                 close(fd);
403                 ret = i;
404                 goto exist_err;
405         }
406
407         close(fd);
408
409         index = connman_inet_ifindex(data->if_name);
410         if (index < 0) {
411                 connman_error("Failed to get tun ifindex");
412                 stop_vpn(provider);
413                 ret = -EIO;
414                 goto exist_err;
415         }
416         vpn_provider_set_index(provider, index);
417
418         return 0;
419
420 exist_err:
421         return ret;
422 }
423
424 static gboolean is_numeric(const char *str)
425 {
426         gint i;
427
428         if(!str || !(*str))
429                 return false;
430
431         for(i = 0; str[i] ; i++) {
432                 if(!g_ascii_isdigit(str[i]))
433                         return false;
434         }
435
436         return true;
437 }
438
439 static gint get_gid(const char *group_name)
440 {
441         gint gid = -1;
442         struct group *grp;
443
444         if(!group_name || !(*group_name))
445                 return gid;
446
447         if (is_numeric(group_name)) {
448                 gid_t group_id = (gid_t)g_ascii_strtoull(group_name, NULL, 10);
449                 grp = getgrgid(group_id);
450         } else {
451                 grp = getgrnam(group_name);
452         }
453
454         if (grp)
455                 gid = grp->gr_gid;
456
457         return gid;
458 }
459
460 static gint get_uid(const char *user_name)
461 {
462         gint uid = -1;
463         struct passwd *pw;
464
465         if(!user_name || !(*user_name))
466                 return uid;
467
468         if (is_numeric(user_name)) {
469                 uid_t user_id = (uid_t)g_ascii_strtoull(user_name, NULL, 10);
470                 pw = getpwuid(user_id);
471         } else {
472                 pw = getpwnam(user_name);
473         }
474
475         if (pw)
476                 uid = pw->pw_uid;
477
478         return uid;
479 }
480
481 static gint get_supplementary_gids(gchar **groups, gid_t **gid_list)
482 {
483         gint group_count = 0;
484         gid_t *list = NULL;
485         int i;
486
487         if (groups) {
488                 for(i = 0; groups[i]; i++) {
489                         group_count++;
490
491                         list = (gid_t*)g_try_realloc(list,
492                                                 sizeof(gid_t) * group_count);
493
494                         if (!list) {
495                                 DBG("cannot allocate supplementary group list");
496                                 break;
497                         }
498
499                         list[i] = get_gid(groups[i]);
500                 }
501         }
502
503         *gid_list = list;
504
505         return group_count;
506 }
507
508 static void vpn_task_setup(gpointer user_data)
509 {
510         struct vpn_plugin_data *data;
511         gint uid;
512         gint gid;
513         gid_t *gid_list = NULL;
514         size_t gid_list_size;
515         const gchar *user;
516         const gchar *group;
517         gchar **suppl_groups;
518
519         data = user_data;
520         user = vpn_settings_get_binary_user(data);
521         group = vpn_settings_get_binary_group(data);
522         suppl_groups = vpn_settings_get_binary_supplementary_groups(data);
523
524         uid = get_uid(user);
525         gid = get_gid(group);
526         gid_list_size = get_supplementary_gids(suppl_groups, &gid_list);
527
528         DBG("vpn_task_setup uid:%d gid:%d supplementary group list size:%zu",
529                                         uid, gid, gid_list_size);
530
531
532         /* Change group if proper group name was set, requires CAP_SETGID.*/
533         if (gid > 0 && setgid(gid))
534                 connman_error("error setting gid %d %s", gid, strerror(errno));
535
536         /* Set the supplementary groups if list exists, requires CAP_SETGID. */
537         if (gid_list_size && gid_list && setgroups(gid_list_size, gid_list))
538                 connman_error("error setting gid list %s", strerror(errno));
539
540         /* Change user for the task if set, requires CAP_SETUID */
541         if (uid > 0 && setuid(uid))
542                 connman_error("error setting uid %d %s", uid, strerror(errno));
543 }
544
545
546 static gboolean update_provider_state(gpointer data)
547 {
548         struct vpn_provider *provider = data;
549         struct vpn_data *vpn_data;
550         int index;
551
552         DBG("");
553
554         vpn_data = vpn_provider_get_data(provider);
555
556         index = vpn_provider_get_index(provider);
557         DBG("index to watch %d", index);
558         vpn_provider_ref(provider);
559         vpn_data->watch = vpn_rtnl_add_newlink_watch(index,
560                                                 vpn_newlink, provider);
561         connman_inet_ifup(index);
562
563         return FALSE;
564 }
565
566 static int vpn_connect(struct vpn_provider *provider,
567                         vpn_provider_connect_cb_t cb,
568                         const char *dbus_sender, void *user_data)
569 {
570         struct vpn_data *data = vpn_provider_get_data(provider);
571         struct vpn_driver_data *vpn_driver_data;
572         struct vpn_plugin_data *vpn_plugin_data;
573         const char *name;
574         int ret = 0, tun_flags = IFF_TUN;
575         enum vpn_state state = VPN_STATE_UNKNOWN;
576
577         if (data)
578                 state = data->state;
579
580         DBG("data %p state %d", data, state);
581
582         switch (state) {
583         case VPN_STATE_UNKNOWN:
584                 data = g_try_new0(struct vpn_data, 1);
585                 if (!data)
586                         return -ENOMEM;
587
588                 data->provider = vpn_provider_ref(provider);
589                 data->watch = 0;
590                 data->flags = 0;
591                 data->task = NULL;
592
593                 vpn_provider_set_data(provider, data);
594                 /* fall through */
595
596         case VPN_STATE_DISCONNECT:
597         case VPN_STATE_IDLE:
598         case VPN_STATE_FAILURE:
599         case VPN_STATE_AUTH_FAILURE:
600                 data->state = VPN_STATE_IDLE;
601                 break;
602
603         case VPN_STATE_CONNECT:
604                 return -EINPROGRESS;
605
606         case VPN_STATE_READY:
607                 return -EISCONN;
608         }
609
610         name = vpn_provider_get_driver_name(provider);
611         if (!name)
612                 return -EINVAL;
613
614         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
615
616         if (!vpn_driver_data || !vpn_driver_data->vpn_driver) {
617                 ret = -EINVAL;
618                 goto exist_err;
619         }
620
621         if (!(vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_TUN)) {
622                 if (vpn_driver_data->vpn_driver->device_flags) {
623                         tun_flags = vpn_driver_data->vpn_driver->device_flags(provider);
624                 }
625                 ret = vpn_create_tun(provider, tun_flags);
626                 if (ret < 0)
627                         goto exist_err;
628         }
629
630
631         if (vpn_driver_data && vpn_driver_data->vpn_driver &&
632                         vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_DAEMON) {
633
634                 ret = vpn_driver_data->vpn_driver->connect(provider,
635                                                 NULL, NULL, NULL, NULL, NULL);
636                 if (ret) {
637                         stop_vpn(provider);
638                         goto exist_err;
639                 }
640
641                 DBG("%s started with dev %s",
642                         vpn_driver_data->provider_driver.name, data->if_name);
643
644                 data->state = VPN_STATE_CONNECT;
645
646                 g_timeout_add(1, update_provider_state, provider);
647                 return -EINPROGRESS;
648         }
649
650         vpn_plugin_data =
651                 vpn_settings_get_vpn_plugin_config(vpn_driver_data->name);
652         data->task = connman_task_create(vpn_driver_data->program,
653                                         vpn_task_setup, vpn_plugin_data);
654
655         if (!data->task) {
656                 ret = -ENOMEM;
657                 stop_vpn(provider);
658                 goto exist_err;
659         }
660
661         if (connman_task_set_notify(data->task, "notify",
662                                         vpn_notify, provider)) {
663                 ret = -ENOMEM;
664                 stop_vpn(provider);
665                 connman_task_destroy(data->task);
666                 data->task = NULL;
667                 goto exist_err;
668         }
669
670         ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
671                                                 data->if_name, cb, dbus_sender,
672                                                 user_data);
673         if (ret < 0 && ret != -EINPROGRESS) {
674                 stop_vpn(provider);
675                 connman_task_destroy(data->task);
676                 data->task = NULL;
677                 goto exist_err;
678         }
679
680         DBG("%s started with dev %s",
681                 vpn_driver_data->provider_driver.name, data->if_name);
682
683         data->state = VPN_STATE_CONNECT;
684
685         return -EINPROGRESS;
686
687 exist_err:
688         vpn_provider_set_index(provider, -1);
689         vpn_provider_set_data(provider, NULL);
690         vpn_provider_unref(data->provider);
691         g_free(data->if_name);
692         g_free(data);
693
694         return ret;
695 }
696
697 static int vpn_probe(struct vpn_provider *provider)
698 {
699         return 0;
700 }
701
702 static int vpn_disconnect(struct vpn_provider *provider)
703 {
704         struct vpn_data *data = vpn_provider_get_data(provider);
705         struct vpn_driver_data *vpn_driver_data;
706         const char *name;
707
708         DBG("disconnect provider %p:", provider);
709
710         if (!data)
711                 return 0;
712
713         name = vpn_provider_get_driver_name(provider);
714         if (!name)
715                 return 0;
716
717         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
718         if (vpn_driver_data->vpn_driver->disconnect)
719                 vpn_driver_data->vpn_driver->disconnect(provider);
720
721         if (data->watch != 0) {
722                 vpn_provider_unref(provider);
723                 vpn_rtnl_remove_watch(data->watch);
724                 data->watch = 0;
725         }
726
727         data->state = VPN_STATE_DISCONNECT;
728
729         if (!vpn_driver_data->vpn_driver->disconnect) {
730                 DBG("Driver has no disconnect() implementation, set provider "
731                                         "state to disconnect.");
732                 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT);
733         }
734
735         if (data->task)
736                 connman_task_stop(data->task);
737
738         return 0;
739 }
740
741 static int vpn_remove(struct vpn_provider *provider)
742 {
743         struct vpn_data *data;
744         struct vpn_driver_data *driver_data;
745         const char *name;
746         int err = 0;
747
748         data = vpn_provider_get_data(provider);
749         name = vpn_provider_get_driver_name(provider);
750
751         if (!data)
752                 goto call_remove;
753
754         if (data->watch != 0) {
755                 vpn_provider_unref(provider);
756                 vpn_rtnl_remove_watch(data->watch);
757                 data->watch = 0;
758         }
759
760         if (data->task)
761                 connman_task_stop(data->task);
762
763         g_usleep(G_USEC_PER_SEC);
764         stop_vpn(provider);
765
766 call_remove:
767         if (!name)
768                 return 0;
769
770         driver_data = g_hash_table_lookup(driver_hash, name);
771
772         if (driver_data && driver_data->vpn_driver->remove)
773                 err = driver_data->vpn_driver->remove(provider);
774
775         if (err)
776                 DBG("%p vpn_driver->remove() returned %d", provider, err);
777
778         return err;
779 }
780
781 static int vpn_save(struct vpn_provider *provider, GKeyFile *keyfile)
782 {
783         struct vpn_driver_data *vpn_driver_data;
784         const char *name;
785
786         name = vpn_provider_get_driver_name(provider);
787         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
788         if (vpn_driver_data &&
789                         vpn_driver_data->vpn_driver->save)
790                 return vpn_driver_data->vpn_driver->save(provider, keyfile);
791
792         return 0;
793 }
794
795 static int vpn_route_env_parse(struct vpn_provider *provider, const char *key,
796                         int *family, unsigned long *idx,
797                         enum vpn_provider_route_type *type)
798 {
799         struct vpn_driver_data *vpn_driver_data = NULL;
800         const char *name = NULL;
801
802         if (!provider)
803                 return -EINVAL;
804
805         name = vpn_provider_get_driver_name(provider);
806         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
807
808         if (vpn_driver_data && vpn_driver_data->vpn_driver->route_env_parse)
809                 return vpn_driver_data->vpn_driver->route_env_parse(provider, key,
810                         family, idx, type);
811
812         return 0;
813 }
814
815 int vpn_register(const char *name, struct vpn_driver *vpn_driver,
816                         const char *program)
817 {
818         struct vpn_driver_data *data;
819
820         data = g_try_new0(struct vpn_driver_data, 1);
821         if (!data)
822                 return -ENOMEM;
823
824         data->name = name;
825         data->program = program;
826
827         if (vpn_settings_parse_vpn_plugin_config(data->name) != 0)
828                 DBG("No configuration provided for VPN plugin %s", data->name);
829
830         data->vpn_driver = vpn_driver;
831
832         data->provider_driver.name = name;
833         data->provider_driver.disconnect = vpn_disconnect;
834         data->provider_driver.connect = vpn_connect;
835         data->provider_driver.probe = vpn_probe;
836         data->provider_driver.remove = vpn_remove;
837         data->provider_driver.save = vpn_save;
838         data->provider_driver.set_state = vpn_set_state;
839         data->provider_driver.route_env_parse = vpn_route_env_parse;
840
841         if (!driver_hash)
842                 driver_hash = g_hash_table_new_full(g_str_hash,
843                                                         g_str_equal,
844                                                         NULL, g_free);
845
846         if (!driver_hash) {
847                 connman_error("driver_hash not initialized for %s", name);
848                 g_free(data);
849                 return -ENOMEM;
850         }
851
852         g_hash_table_replace(driver_hash, (char *)name, data);
853
854         vpn_provider_driver_register(&data->provider_driver);
855
856         return 0;
857 }
858
859 void vpn_unregister(const char *name)
860 {
861         struct vpn_driver_data *data;
862
863         data = g_hash_table_lookup(driver_hash, name);
864         if (!data)
865                 return;
866
867         vpn_provider_driver_unregister(&data->provider_driver);
868         vpn_settings_delete_vpn_plugin_config(name);
869
870         g_hash_table_remove(driver_hash, name);
871
872         if (g_hash_table_size(driver_hash) == 0)
873                 g_hash_table_destroy(driver_hash);
874 }