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/provider.h>
43 #include <connman/log.h>
44 #include <connman/rtnl.h>
45 #include <connman/task.h>
46 #include <connman/inet.h>
51 struct connman_provider *provider;
56 struct connman_task *task;
59 struct vpn_driver_data {
62 struct vpn_driver *vpn_driver;
63 struct connman_provider_driver provider_driver;
66 GHashTable *driver_hash = NULL;
68 static int stop_vpn(struct connman_provider *provider)
70 struct vpn_data *data = connman_provider_get_data(provider);
71 struct vpn_driver_data *vpn_driver_data;
79 name = connman_provider_get_driver_name(provider);
83 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
85 if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
86 vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
89 memset(&ifr, 0, sizeof(ifr));
90 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
91 sprintf(ifr.ifr_name, "%s", data->if_name);
93 fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
96 connman_error("Failed to open /dev/net/tun to device %s: %s",
97 data->if_name, strerror(errno));
101 if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
103 connman_error("Failed to TUNSETIFF for device %s to it: %s",
104 data->if_name, strerror(errno));
109 if (ioctl(fd, TUNSETPERSIST, 0)) {
111 connman_error("Failed to set tun device %s nonpersistent: %s",
112 data->if_name, strerror(errno));
117 DBG("Killed tun device %s", data->if_name);
121 void vpn_died(struct connman_task *task, int exit_code, void *user_data)
123 struct connman_provider *provider = user_data;
124 struct vpn_data *data = connman_provider_get_data(provider);
125 int state = VPN_STATE_FAILURE;
126 enum connman_provider_error ret;
128 DBG("provider %p data %p", provider, data);
136 connman_provider_set_data(provider, NULL);
138 if (data->watch != 0) {
139 connman_provider_unref(provider);
140 connman_rtnl_remove_watch(data->watch);
145 if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) {
147 struct vpn_driver_data *vpn_data = NULL;
149 name = connman_provider_get_driver_name(provider);
151 vpn_data = g_hash_table_lookup(driver_hash, name);
153 if (vpn_data != NULL &&
154 vpn_data->vpn_driver->error_code != NULL)
155 ret = vpn_data->vpn_driver->error_code(exit_code);
157 ret = CONNMAN_PROVIDER_ERROR_UNKNOWN;
159 connman_provider_indicate_error(provider, ret);
161 connman_provider_set_state(provider,
162 CONNMAN_PROVIDER_STATE_IDLE);
164 connman_provider_set_index(provider, -1);
167 connman_provider_unref(data->provider);
168 g_free(data->if_name);
172 connman_task_destroy(task);
175 int vpn_set_ifname(struct connman_provider *provider, const char *ifname)
177 struct vpn_data *data = connman_provider_get_data(provider);
180 if (ifname == NULL || data == NULL)
183 index = connman_inet_ifindex(ifname);
187 if (data->if_name != NULL)
188 g_free(data->if_name);
190 data->if_name = (char *)g_strdup(ifname);
191 connman_provider_set_index(provider, index);
196 static void vpn_newlink(unsigned flags, unsigned change, void *user_data)
198 struct connman_provider *provider = user_data;
199 struct vpn_data *data = connman_provider_get_data(provider);
201 if ((data->flags & IFF_UP) != (flags & IFF_UP)) {
202 if (flags & IFF_UP) {
203 data->state = VPN_STATE_READY;
204 connman_provider_set_state(provider,
205 CONNMAN_PROVIDER_STATE_READY);
211 static DBusMessage *vpn_notify(struct connman_task *task,
212 DBusMessage *msg, void *user_data)
214 struct connman_provider *provider = user_data;
215 struct vpn_data *data;
216 struct vpn_driver_data *vpn_driver_data;
220 data = connman_provider_get_data(provider);
222 name = connman_provider_get_driver_name(provider);
226 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
227 if (vpn_driver_data == NULL)
230 state = vpn_driver_data->vpn_driver->notify(msg, provider);
232 case VPN_STATE_CONNECT:
233 case VPN_STATE_READY:
234 index = connman_provider_get_index(provider);
235 connman_provider_ref(provider);
236 data->watch = connman_rtnl_add_newlink_watch(index,
237 vpn_newlink, provider);
238 connman_inet_ifup(index);
241 case VPN_STATE_UNKNOWN:
243 case VPN_STATE_DISCONNECT:
244 case VPN_STATE_FAILURE:
245 connman_provider_set_state(provider,
246 CONNMAN_PROVIDER_STATE_DISCONNECT);
249 case VPN_STATE_AUTH_FAILURE:
250 connman_provider_indicate_error(provider,
251 CONNMAN_PROVIDER_ERROR_AUTH_FAILED);
258 static int vpn_create_tun(struct connman_provider *provider)
260 struct vpn_data *data = connman_provider_get_data(provider);
268 fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
271 connman_error("Failed to open /dev/net/tun: %s",
277 memset(&ifr, 0, sizeof(ifr));
278 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
280 for (i = 0; i < 256; i++) {
281 sprintf(ifr.ifr_name, "vpn%d", i);
283 if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
288 connman_error("Failed to find available tun device");
294 data->if_name = (char *)g_strdup(ifr.ifr_name);
295 if (data->if_name == NULL) {
296 connman_error("Failed to allocate memory");
302 if (ioctl(fd, TUNSETPERSIST, 1)) {
304 connman_error("Failed to set tun persistent: %s",
313 index = connman_inet_ifindex(data->if_name);
315 connman_error("Failed to get tun ifindex");
320 connman_provider_set_index(provider, index);
328 static int vpn_connect(struct connman_provider *provider)
330 struct vpn_data *data = connman_provider_get_data(provider);
331 struct vpn_driver_data *vpn_driver_data;
338 data = g_try_new0(struct vpn_data, 1);
342 data->provider = connman_provider_ref(provider);
346 data->state = VPN_STATE_IDLE;
348 connman_provider_set_data(provider, data);
350 name = connman_provider_get_driver_name(provider);
354 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
356 if (vpn_driver_data == NULL || vpn_driver_data->vpn_driver == NULL) {
361 if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
362 ret = vpn_create_tun(provider);
367 data->task = connman_task_create(vpn_driver_data->program);
369 if (data->task == NULL) {
375 if (connman_task_set_notify(data->task, "notify",
376 vpn_notify, provider)) {
379 connman_task_destroy(data->task);
384 ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
388 connman_task_destroy(data->task);
393 DBG("%s started with dev %s",
394 vpn_driver_data->provider_driver.name, data->if_name);
396 data->state = VPN_STATE_CONNECT;
401 connman_provider_set_index(provider, -1);
402 connman_provider_set_data(provider, NULL);
403 connman_provider_unref(data->provider);
404 g_free(data->if_name);
410 static int vpn_probe(struct connman_provider *provider)
415 static int vpn_disconnect(struct connman_provider *provider)
417 struct vpn_data *data = connman_provider_get_data(provider);
418 struct vpn_driver_data *vpn_driver_data;
421 DBG("disconnect provider %p:", provider);
426 name = connman_provider_get_driver_name(provider);
430 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
431 if (vpn_driver_data->vpn_driver->disconnect)
432 vpn_driver_data->vpn_driver->disconnect();
434 if (data->watch != 0) {
435 connman_provider_unref(provider);
436 connman_rtnl_remove_watch(data->watch);
440 data->state = VPN_STATE_DISCONNECT;
441 connman_task_stop(data->task);
446 static int vpn_remove(struct connman_provider *provider)
448 struct vpn_data *data;
450 data = connman_provider_get_data(provider);
454 if (data->watch != 0) {
455 connman_provider_unref(provider);
456 connman_rtnl_remove_watch(data->watch);
460 connman_task_stop(data->task);
462 g_usleep(G_USEC_PER_SEC);
467 static int vpn_save (struct connman_provider *provider, GKeyFile *keyfile)
469 struct vpn_driver_data *vpn_driver_data;
472 name = connman_provider_get_driver_name(provider);
473 vpn_driver_data = g_hash_table_lookup(driver_hash, name);
474 if (vpn_driver_data != NULL &&
475 vpn_driver_data->vpn_driver->save != NULL)
476 return vpn_driver_data->vpn_driver->save(provider, keyfile);
481 int vpn_register(const char *name, struct vpn_driver *vpn_driver,
484 struct vpn_driver_data *data;
486 data = g_try_new0(struct vpn_driver_data, 1);
491 data->program = program;
493 data->vpn_driver = vpn_driver;
495 data->provider_driver.name = name;
496 data->provider_driver.disconnect = vpn_disconnect;
497 data->provider_driver.connect = vpn_connect;
498 data->provider_driver.probe = vpn_probe;
499 data->provider_driver.remove = vpn_remove;
500 data->provider_driver.save = vpn_save;
502 if (driver_hash == NULL)
503 driver_hash = g_hash_table_new_full(g_str_hash,
507 if (driver_hash == NULL) {
508 connman_error("driver_hash not initialized for %s", name);
513 g_hash_table_replace(driver_hash, (char *)name, data);
515 connman_provider_driver_register(&data->provider_driver);
520 void vpn_unregister(const char *name)
522 struct vpn_driver_data *data;
524 data = g_hash_table_lookup(driver_hash, name);
528 connman_provider_driver_unregister(&data->provider_driver);
530 g_hash_table_remove(driver_hash, name);
532 if (g_hash_table_size(driver_hash) == 0)
533 g_hash_table_destroy(driver_hash);