5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
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.
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.
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
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <linux/if_tun.h>
38 #include <dbus/dbus.h>
40 #include <glib/gprintf.h>
42 #include <connman/log.h>
43 #include <connman/rtnl.h>
44 #include <connman/task.h>
45 #include <connman/inet.h>
47 #include "../vpn-rtnl.h"
48 #include "../vpn-provider.h"
53 struct vpn_provider *provider;
58 struct connman_task *task;
61 struct vpn_driver_data {
64 struct vpn_driver *vpn_driver;
65 struct vpn_provider_driver provider_driver;
68 GHashTable *driver_hash = NULL;
70 static int stop_vpn(struct vpn_provider *provider)
72 struct vpn_data *data = vpn_provider_get_data(provider);
73 struct vpn_driver_data *vpn_driver_data;
81 name = vpn_provider_get_driver_name(provider);
85 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
87 if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
88 vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
91 memset(&ifr, 0, sizeof(ifr));
92 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
93 sprintf(ifr.ifr_name, "%s", data->if_name);
95 fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
98 connman_error("Failed to open /dev/net/tun to device %s: %s",
99 data->if_name, strerror(errno));
103 if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
105 connman_error("Failed to TUNSETIFF for device %s to it: %s",
106 data->if_name, strerror(errno));
111 if (ioctl(fd, TUNSETPERSIST, 0)) {
113 connman_error("Failed to set tun device %s nonpersistent: %s",
114 data->if_name, strerror(errno));
119 DBG("Killed tun device %s", data->if_name);
123 void vpn_died(struct connman_task *task, int exit_code, void *user_data)
125 struct vpn_provider *provider = user_data;
126 struct vpn_data *data = vpn_provider_get_data(provider);
127 int state = VPN_STATE_FAILURE;
128 enum vpn_provider_error ret;
130 DBG("provider %p data %p", provider, data);
138 vpn_provider_set_data(provider, NULL);
140 if (data->watch != 0) {
141 vpn_provider_unref(provider);
142 vpn_rtnl_remove_watch(data->watch);
147 if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) {
149 struct vpn_driver_data *vpn_data = NULL;
151 name = vpn_provider_get_driver_name(provider);
153 vpn_data = g_hash_table_lookup(driver_hash, name);
155 if (vpn_data != NULL &&
156 vpn_data->vpn_driver->error_code != NULL)
157 ret = vpn_data->vpn_driver->error_code(exit_code);
159 ret = VPN_PROVIDER_ERROR_UNKNOWN;
161 vpn_provider_indicate_error(provider, ret);
163 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
165 vpn_provider_set_index(provider, -1);
168 vpn_provider_unref(data->provider);
169 g_free(data->if_name);
173 connman_task_destroy(task);
176 int vpn_set_ifname(struct vpn_provider *provider, const char *ifname)
178 struct vpn_data *data = vpn_provider_get_data(provider);
181 if (ifname == NULL || data == NULL)
184 index = connman_inet_ifindex(ifname);
188 if (data->if_name != NULL)
189 g_free(data->if_name);
191 data->if_name = (char *)g_strdup(ifname);
192 vpn_provider_set_index(provider, index);
197 static void vpn_newlink(unsigned flags, unsigned change, void *user_data)
199 struct vpn_provider *provider = user_data;
200 struct vpn_data *data = vpn_provider_get_data(provider);
202 if ((data->flags & IFF_UP) != (flags & IFF_UP)) {
203 if (flags & IFF_UP) {
204 data->state = VPN_STATE_READY;
205 vpn_provider_set_state(provider,
206 VPN_PROVIDER_STATE_READY);
212 static DBusMessage *vpn_notify(struct connman_task *task,
213 DBusMessage *msg, void *user_data)
215 struct vpn_provider *provider = user_data;
216 struct vpn_data *data;
217 struct vpn_driver_data *vpn_driver_data;
221 data = vpn_provider_get_data(provider);
223 name = vpn_provider_get_driver_name(provider);
227 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
228 if (vpn_driver_data == NULL)
231 state = vpn_driver_data->vpn_driver->notify(msg, provider);
233 case VPN_STATE_CONNECT:
234 case VPN_STATE_READY:
235 index = vpn_provider_get_index(provider);
236 vpn_provider_ref(provider);
237 data->watch = vpn_rtnl_add_newlink_watch(index,
238 vpn_newlink, provider);
239 connman_inet_ifup(index);
242 case VPN_STATE_UNKNOWN:
244 case VPN_STATE_DISCONNECT:
245 case VPN_STATE_FAILURE:
246 vpn_provider_set_state(provider,
247 VPN_PROVIDER_STATE_DISCONNECT);
250 case VPN_STATE_AUTH_FAILURE:
251 vpn_provider_indicate_error(provider,
252 VPN_PROVIDER_ERROR_AUTH_FAILED);
259 static int vpn_create_tun(struct vpn_provider *provider)
261 struct vpn_data *data = vpn_provider_get_data(provider);
269 fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
272 connman_error("Failed to open /dev/net/tun: %s",
278 memset(&ifr, 0, sizeof(ifr));
279 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
281 for (i = 0; i < 256; i++) {
282 sprintf(ifr.ifr_name, "vpn%d", i);
284 if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
289 connman_error("Failed to find available tun device");
295 data->if_name = (char *)g_strdup(ifr.ifr_name);
296 if (data->if_name == NULL) {
297 connman_error("Failed to allocate memory");
303 if (ioctl(fd, TUNSETPERSIST, 1)) {
305 connman_error("Failed to set tun persistent: %s",
314 index = connman_inet_ifindex(data->if_name);
316 connman_error("Failed to get tun ifindex");
321 vpn_provider_set_index(provider, index);
329 static int vpn_connect(struct vpn_provider *provider)
331 struct vpn_data *data = vpn_provider_get_data(provider);
332 struct vpn_driver_data *vpn_driver_data;
339 data = g_try_new0(struct vpn_data, 1);
343 data->provider = vpn_provider_ref(provider);
347 data->state = VPN_STATE_IDLE;
349 vpn_provider_set_data(provider, data);
351 name = vpn_provider_get_driver_name(provider);
355 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
357 if (vpn_driver_data == NULL || vpn_driver_data->vpn_driver == NULL) {
362 if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
363 ret = vpn_create_tun(provider);
368 data->task = connman_task_create(vpn_driver_data->program);
370 if (data->task == NULL) {
376 if (connman_task_set_notify(data->task, "notify",
377 vpn_notify, provider)) {
380 connman_task_destroy(data->task);
385 ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
389 connman_task_destroy(data->task);
394 DBG("%s started with dev %s",
395 vpn_driver_data->provider_driver.name, data->if_name);
397 data->state = VPN_STATE_CONNECT;
402 vpn_provider_set_index(provider, -1);
403 vpn_provider_set_data(provider, NULL);
404 vpn_provider_unref(data->provider);
405 g_free(data->if_name);
411 static int vpn_probe(struct vpn_provider *provider)
416 static int vpn_disconnect(struct vpn_provider *provider)
418 struct vpn_data *data = vpn_provider_get_data(provider);
419 struct vpn_driver_data *vpn_driver_data;
422 DBG("disconnect provider %p:", provider);
427 name = vpn_provider_get_driver_name(provider);
431 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
432 if (vpn_driver_data->vpn_driver->disconnect)
433 vpn_driver_data->vpn_driver->disconnect();
435 if (data->watch != 0) {
436 vpn_provider_unref(provider);
437 vpn_rtnl_remove_watch(data->watch);
441 data->state = VPN_STATE_DISCONNECT;
442 connman_task_stop(data->task);
447 static int vpn_remove(struct vpn_provider *provider)
449 struct vpn_data *data;
451 data = vpn_provider_get_data(provider);
455 if (data->watch != 0) {
456 vpn_provider_unref(provider);
457 vpn_rtnl_remove_watch(data->watch);
461 connman_task_stop(data->task);
463 g_usleep(G_USEC_PER_SEC);
468 static int vpn_save(struct vpn_provider *provider, GKeyFile *keyfile)
470 struct vpn_driver_data *vpn_driver_data;
473 name = vpn_provider_get_driver_name(provider);
474 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
475 if (vpn_driver_data != NULL &&
476 vpn_driver_data->vpn_driver->save != NULL)
477 return vpn_driver_data->vpn_driver->save(provider, keyfile);
482 int vpn_register(const char *name, struct vpn_driver *vpn_driver,
485 struct vpn_driver_data *data;
487 data = g_try_new0(struct vpn_driver_data, 1);
492 data->program = program;
494 data->vpn_driver = vpn_driver;
496 data->provider_driver.name = name;
497 data->provider_driver.disconnect = vpn_disconnect;
498 data->provider_driver.connect = vpn_connect;
499 data->provider_driver.probe = vpn_probe;
500 data->provider_driver.remove = vpn_remove;
501 data->provider_driver.save = vpn_save;
503 if (driver_hash == NULL)
504 driver_hash = g_hash_table_new_full(g_str_hash,
508 if (driver_hash == NULL) {
509 connman_error("driver_hash not initialized for %s", name);
514 g_hash_table_replace(driver_hash, (char *)name, data);
516 vpn_provider_driver_register(&data->provider_driver);
521 void vpn_unregister(const char *name)
523 struct vpn_driver_data *data;
525 data = g_hash_table_lookup(driver_hash, name);
529 vpn_provider_driver_unregister(&data->provider_driver);
531 g_hash_table_remove(driver_hash, name);
533 if (g_hash_table_size(driver_hash) == 0)
534 g_hash_table_destroy(driver_hash);