summaryrefslogtreecommitdiff
path: root/plugins/vpn.c
diff options
context:
space:
mode:
authorMohamed Abbas <mabbas@linux.intel.com>2011-11-15 13:06:13 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2011-11-15 13:41:44 +0100
commit43365bffe9cd2f4b0364c3df808a49ffcfc31090 (patch)
treeda3ae3a680ec75c6985dd678a0b8cfe8a17deffb /plugins/vpn.c
parent43a29da43f9d9f518c939d0251bc0f266dff7887 (diff)
downloadconnman-43365bffe9cd2f4b0364c3df808a49ffcfc31090.tar.gz
connman-43365bffe9cd2f4b0364c3df808a49ffcfc31090.tar.bz2
connman-43365bffe9cd2f4b0364c3df808a49ffcfc31090.zip
vpn: Add support to allow ppp tunnelling
pptp and l2tp does not use tun/tab approach so change the vpn.c to allow vpn daemon to create the interface. Now vpn plugin tell vpn to create the device or leave to vpn client. On connection vpn will get the interface name set the index for the provider. This patch is prepared by Jukka Rissanen and it contains Mohamed Abbas original patch + fixes suggested by Daniel Wagner. Jukka fixed memory leak in vpn_set_ifname().
Diffstat (limited to 'plugins/vpn.c')
-rw-r--r--plugins/vpn.c122
1 files changed, 90 insertions, 32 deletions
diff --git a/plugins/vpn.c b/plugins/vpn.c
index 79ec305f..7d55d812 100644
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -66,27 +66,40 @@ struct vpn_driver_data {
GHashTable *driver_hash = NULL;
-static int kill_tun(char *tun_name)
+static int stop_vpn(struct connman_provider *provider)
{
+ struct vpn_data *data = connman_provider_get_data(provider);
+ struct vpn_driver_data *vpn_driver_data;
+ const char *name;
struct ifreq ifr;
int fd, err;
+ if (data == NULL)
+ return -EINVAL;
+
+ name = connman_provider_get_driver_name(provider);
+ vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+
+ if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
+ vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
+ return 0;
+
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
- sprintf(ifr.ifr_name, "%s", tun_name);
+ sprintf(ifr.ifr_name, "%s", data->if_name);
fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0) {
err = -errno;
connman_error("Failed to open /dev/net/tun to device %s: %s",
- tun_name, strerror(errno));
+ data->if_name, strerror(errno));
return err;
}
if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
err = -errno;
connman_error("Failed to TUNSETIFF for device %s to it: %s",
- tun_name, strerror(errno));
+ data->if_name, strerror(errno));
close(fd);
return err;
}
@@ -94,12 +107,12 @@ static int kill_tun(char *tun_name)
if (ioctl(fd, TUNSETPERSIST, 0)) {
err = -errno;
connman_error("Failed to set tun device %s nonpersistent: %s",
- tun_name, strerror(errno));
+ data->if_name, strerror(errno));
close(fd);
return err;
}
close(fd);
- DBG("Killed tun device %s", tun_name);
+ DBG("Killed tun device %s", data->if_name);
return 0;
}
@@ -117,7 +130,7 @@ void vpn_died(struct connman_task *task, int exit_code, void *user_data)
state = data->state;
- kill_tun(data->if_name);
+ stop_vpn(provider);
connman_provider_set_data(provider, NULL);
connman_rtnl_remove_watch(data->watch);
@@ -141,11 +154,34 @@ vpn_exit:
connman_provider_set_index(provider, -1);
connman_provider_unref(data->provider);
+
+ g_free(data->if_name);
g_free(data);
connman_task_destroy(task);
}
+int vpn_set_ifname(struct connman_provider *provider, const char *ifname)
+{
+ struct vpn_data *data = connman_provider_get_data(provider);
+ int index;
+
+ if (ifname == NULL || data == NULL)
+ return -EIO;
+
+ index = connman_inet_ifindex(ifname);
+ if (index < 0)
+ return -EIO;
+
+ if (data->if_name != NULL)
+ g_free(data->if_name);
+
+ data->if_name = (char *)g_strdup(ifname);
+ connman_provider_set_index(provider, index);
+
+ return 0;
+}
+
static void vpn_newlink(unsigned flags, unsigned change, void *user_data)
{
struct connman_provider *provider = user_data;
@@ -202,32 +238,15 @@ static void vpn_notify(struct connman_task *task,
}
}
-static int vpn_connect(struct connman_provider *provider)
+static int vpn_create_tun(struct connman_provider *provider)
{
struct vpn_data *data = connman_provider_get_data(provider);
- struct vpn_driver_data *vpn_driver_data;
struct ifreq ifr;
- const char *name;
int i, fd, index;
int ret = 0;
- if (data != NULL)
- return -EISCONN;
-
- data = g_try_new0(struct vpn_data, 1);
if (data == NULL)
- return -ENOMEM;
-
- data->provider = connman_provider_ref(provider);
- data->watch = 0;
- data->flags = 0;
- data->task = NULL;
- data->state = VPN_STATE_IDLE;
-
- connman_provider_set_data(provider, data);
-
- name = connman_provider_get_driver_name(provider);
- vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+ return -EISCONN;
fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0) {
@@ -277,24 +296,63 @@ static int vpn_connect(struct connman_provider *provider)
index = connman_inet_ifindex(data->if_name);
if (index < 0) {
connman_error("Failed to get tun ifindex");
- kill_tun(data->if_name);
+ stop_vpn(provider);
ret = -EIO;
goto exist_err;
}
connman_provider_set_index(provider, index);
+ return 0;
+
+exist_err:
+ return ret;
+}
+
+static int vpn_connect(struct connman_provider *provider)
+{
+ struct vpn_data *data = connman_provider_get_data(provider);
+ struct vpn_driver_data *vpn_driver_data;
+ const char *name;
+ int ret = 0;
+
+ if (data != NULL)
+ return -EISCONN;
+
+ data = g_try_new0(struct vpn_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->provider = connman_provider_ref(provider);
+ data->watch = 0;
+ data->flags = 0;
+ data->task = NULL;
+ data->state = VPN_STATE_IDLE;
+
+ connman_provider_set_data(provider, data);
+
+ name = connman_provider_get_driver_name(provider);
+ vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+
+ if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
+ vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
+
+ ret = vpn_create_tun(provider);
+ if (ret < 0)
+ goto exist_err;
+ }
+
data->task = connman_task_create(vpn_driver_data->program);
if (data->task == NULL) {
ret = -ENOMEM;
- kill_tun(data->if_name);
+ stop_vpn(provider);
goto exist_err;
}
if (connman_task_set_notify(data->task, "notify",
vpn_notify, provider)) {
ret = -ENOMEM;
- kill_tun(data->if_name);
+ stop_vpn(provider);
connman_task_destroy(data->task);
data->task = NULL;
goto exist_err;
@@ -303,7 +361,7 @@ static int vpn_connect(struct connman_provider *provider)
ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
data->if_name);
if (ret < 0) {
- kill_tun(data->if_name);
+ stop_vpn(provider);
connman_task_destroy(data->task);
data->task = NULL;
goto exist_err;
@@ -320,6 +378,7 @@ exist_err:
connman_provider_set_index(provider, -1);
connman_provider_set_data(provider, NULL);
connman_provider_unref(data->provider);
+ g_free(data->if_name);
g_free(data);
return ret;
@@ -361,7 +420,6 @@ static int vpn_remove(struct connman_provider *provider)
struct vpn_data *data;
data = connman_provider_get_data(provider);
- connman_provider_set_data(provider, NULL);
if (data == NULL)
return 0;
@@ -371,7 +429,7 @@ static int vpn_remove(struct connman_provider *provider)
connman_task_stop(data->task);
g_usleep(G_USEC_PER_SEC);
- kill_tun(data->if_name);
+ stop_vpn(provider);
return 0;
}