Here's a start at VPN support. It works with the openconnect client, but
should be fairly simple to make it work with vpnc too.
It's not complete, and it's not entirely pretty, but it lets me connect
to the VPN. There's no corresponding connman-gnome support yet, so you
have to run the 'test/join_vpn' script with hostname and login cookie as
arguments.
It then invokes openconnect with a "script" which uses DBus to send the
network information back to connman.
It brings up the VPN device and sets the address appropriately, although
see the /* Marcel, please don't hurt me */ comment on that. It doesn't
attempt to handle routing any further than that, so far -- we need to
address that somehow, but it belongs in the ConnMan core and needs
further discussion.
git://git.infradead.org/~dwmw2/connman-openconnect.git
diff --git a/configure.ac b/configure.ac
index daa40c3..8dbd21f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -262,6 +262,21 @@ AC_ARG_ENABLE(fake, AC_HELP_STRING([--enable-fake],
[enable fake device support]), [enable_fake=${enableval}])
AM_CONDITIONAL(FAKE, test "${enable_fake}" = "yes")
+AC_ARG_WITH(openconnect, AC_HELP_STRING([--with-openconnect=PROGRAM],
+ [specify location of openconnect binary]),
[path_openconnect=${withval}])
+
+AC_ARG_ENABLE(openconnect, AC_HELP_STRING([--enable-openconnect],
+ [enable OpenConnect VPN support]),
[enable_openconnect=${enableval}])
+if (test "${enable_openconnect}" = "yes"); then
+ if (test -z "${path_openconnect}"); then
+ AC_PATH_PROG(OPENCONNECT, [openconnect], [],
$PATH:/sbin:/usr/sbin)
+ else
+ OPENCONNECTC="${path_openconnectc}"
+ AC_SUBST(OPENCONNECT)
+ fi
+fi
+AM_CONDITIONAL(OPENCONNECT, test "${enable_openconnect}" = "yes")
+
AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
[don't install configuration and data files]),
[enable_datafiles=${enableval}])
diff --git a/include/device.h b/include/device.h
index 17a2a0c..17c0a32 100644
--- a/include/device.h
+++ b/include/device.h
@@ -46,6 +46,7 @@ enum connman_device_type {
CONNMAN_DEVICE_TYPE_NOZOMI = 16,
CONNMAN_DEVICE_TYPE_HUAWEI = 17,
CONNMAN_DEVICE_TYPE_NOVATEL = 18,
+ CONNMAN_DEVICE_TYPE_VPN = 19,
CONNMAN_DEVICE_TYPE_VENDOR = 10000,
};
diff --git a/include/network.h b/include/network.h
index 02caa59..1555313 100644
--- a/include/network.h
+++ b/include/network.h
@@ -43,6 +43,7 @@ enum connman_network_type {
CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN = 9,
CONNMAN_NETWORK_TYPE_HSO = 23,
CONNMAN_NETWORK_TYPE_VENDOR = 10000,
+ CONNMAN_NETWORK_TYPE_VPN = 10001,
};
enum connman_network_protocol {
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index db3977f..bc01025 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -112,6 +112,13 @@ if FAKE
plugin_LTLIBRARIES += fake.la
endif
+if OPENCONNECT
+plugin_LTLIBRARIES += openconnect.la
+openconnect_la_SOURCES = openconnect.c inet.h inet.c
+openconnect_la_CFLAGS = $(AM_CFLAGS) -DOPENCONNECT=\"@openconn...@\" \
+ -DSCRIPTDIR=\""$(scriptdir)"\"
+endif
+
AM_LDFLAGS = -no-undefined -module -avoid-version
statedir = $(localstatedir)/run/connman
diff --git a/plugins/openconnect.c b/plugins/openconnect.c
new file mode 100644
index 0000000..4efc7e0
--- /dev/null
+++ b/plugins/openconnect.c
@@ -0,0 +1,530 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <linux/if_tun.h>
+#include <net/if.h>
+#include <stdint.h>
+
+#include <glib/garray.h>
+#include <glib/gerror.h>
+#include <glib/gmain.h>
+#include <glib/gspawn.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/device.h>
+#include <connman/log.h>
+#include <connman/dbus.h>
+#include <connman/element.h>
+
+#define OPENCONNECT_INTF "org.infradead.openconnect"
+#define OPENCONNECT_PATH "/org/infradead/openconnect"
+
+static const char *busname;
+
+struct oc_net_data {
+ pid_t pid;
+ char *if_name;
+};
+
+static int oc_dev_probe(struct connman_device *device)
+{
+ DBG("");
+
+ return 0;
+}
+
+static void oc_dev_remove(struct connman_device *device)
+{
+ DBG("");
+}
+
+static int kill_tun(char *tun_name)
+{
+ struct ifreq ifr;
+ int fd, i;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ sprintf(ifr.ifr_name, tun_name);
+
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd < 0) {
+ i = -errno;
+ connman_error("Failed to open /dev/net/tun to kill device %s:
%s",
+ tun_name, strerror(errno));
+ return i;
+ }
+
+ if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
+ i = -errno;
+ connman_error("Failed to TUNSETIFF for device %s to kill it:
%s",
+ tun_name, strerror(errno));
+ close(fd);
+ return i;
+ }
+
+ if (ioctl(fd, TUNSETPERSIST, 0)) {
+ i = -errno;
+ connman_error("Failed to set tun device %s nonpersistent: %s",
+ tun_name, strerror(errno));
+ close(fd);
+ return i;
+ }
+ close(fd);
+ DBG("Killed tun device %s", tun_name);
+ return 0;
+}
+
+static void oc_watch_cb(pid_t pid, int status, struct connman_network *network)
+{
+ struct connman_device *device = connman_network_get_device(network);
+ struct oc_net_data *data = connman_network_get_data(network);
+ int error = 0;
+
+ DBG("pid %d status %d network %p", pid, status, network);
+
+ if (WIFEXITED(status)) {
+ error = WEXITSTATUS(status);
+ if (error)
+ connman_error("openconnect exited with error code %d",
+ error);
+ } else if (WIFSTOPPED(status))
+ connman_error("openconnect stopped unexpectedly with signal %d",
+ WSTOPSIG(status));
+ else if (WIFSIGNALED(status))
+ connman_error("openconnect died with signal %d",
+ WTERMSIG(status));
+ else
+ connman_error("openconnect died from an unknown cause");
+
+ waitpid(pid, NULL, WNOHANG);
+ switch(error) {
+ case 2: /* Login failure */
+ connman_error("openconnect reported login failure");
+ break;
+ case 1: /* General failure */
+ connman_error("openconnect reported unspecified failure");
+ break;
+ }
+ kill_tun(data->if_name);
+ connman_device_remove_network(device,
+ connman_network_get_identifier(network));
+}
+
+static int oc_dev_enable(struct connman_device *device)
+{
+ DBG("");
+
+ // create_network(device, "openconnect_vpn");
+ connman_device_set_powered(device, TRUE);
+ return 0;
+}
+
+static int oc_dev_join(struct connman_device *device,
+ struct connman_network *network)
+{
+ struct oc_net_data *data = connman_network_get_data(network);
+ struct ifreq ifr;
+ int oc_fd, fd, i, index;
+ const char *vpnhost, *vpncookie, *cafile;
+ GPtrArray *oc_argv, *oc_envp;
+ GError *error;
+ GSource *oc_watch;
+
+ data = g_try_new0(struct oc_net_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ connman_network_set_data(network, data);
+ /* Setting PROTOCOL_UNKNOWN prevents DHCP */
+ connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_UNKNOWN);
+
+ vpnhost = connman_network_get_string(network, "OpenConnect.Host");
+ if (!vpnhost) {
+ connman_error("OpenConnect.Host not set; cannot enable VPN");
+ return -EINVAL;
+ }
+ vpncookie = connman_network_get_string(network, "OpenConnect.Cookie");
+ if (!vpncookie) {
+ connman_error("OpenConnect.Cookie not set; cannot enable VPN");
+ return -EINVAL;
+ }
+ cafile = connman_network_get_string(network, "OpenConnect.CACert");
+
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd < 0) {
+ i = -errno;
+ connman_error("Failed to open /dev/net/tun: %s",
+ strerror(errno));
+ return i;
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+
+ for (i = 0; i < 256; i++) {
+ sprintf(ifr.ifr_name, "vpn%d", i);
+
+ if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
+ break;
+ }
+ if (i == 256) {
+ connman_error("Failed to find available tun device");
+ close(fd);
+ return -ENODEV;
+ }
+
+ data->if_name = (char *)g_strdup(ifr.ifr_name);
+ if (!data->if_name)
+ return -ENOMEM;
+
+ if (ioctl(fd, TUNSETPERSIST, 1)) {
+ i = -errno;
+ connman_error("Failed to set tun persistent: %s",
+ strerror(errno));
+ close(fd);
+ return i;
+ }
+
+ /* XXX: Should TUNSETOWNER and run openconnect as unprivileged user */
+
+ close(fd);
+
+ index = inet_name2index(data->if_name);
+ if (index < 0) {
+ connman_error("Failed to get tun ifindex");
+ kill_tun(data->if_name);
+ return -EIO;
+ }
+ connman_network_set_index(network, index);
+
+ oc_argv = g_ptr_array_new();
+ g_ptr_array_add(oc_argv, OPENCONNECT);
+
+ if (cafile) {
+ g_ptr_array_add(oc_argv, "--cafile");
+ g_ptr_array_add(oc_argv, (char *)cafile);
+ }
+ g_ptr_array_add(oc_argv, "--syslog");
+ g_ptr_array_add(oc_argv, "--cookie-on-stdin");
+
+ g_ptr_array_add(oc_argv, "--script");
+ g_ptr_array_add(oc_argv, SCRIPTDIR "/openconnect-script");
+
+ g_ptr_array_add(oc_argv, "--interface");
+ g_ptr_array_add(oc_argv, data->if_name);
+
+ g_ptr_array_add(oc_argv, (char *)vpnhost);
+ g_ptr_array_add(oc_argv, NULL);
+
+ oc_envp = g_ptr_array_new();
+ g_ptr_array_add(oc_envp,
+ (char *)g_strdup_printf("connman_busname=%s", busname));
+ g_ptr_array_add(oc_envp,
+ (char *)g_strdup_printf("connman_network=%s",
+
connman_network_get_identifier(network)));
+ g_ptr_array_add(oc_envp, NULL);
+
+ if (!g_spawn_async_with_pipes(NULL, (char **)oc_argv->pdata,
+ (char **)oc_envp->pdata,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, &data->pid,
+ &oc_fd, NULL, NULL, &error)) {
+ g_ptr_array_free(oc_argv, TRUE);
+ connman_error("Openconnect failed to start: %s",
+ error->message);
+ kill_tun(data->if_name);
+ return -EIO;
+ }
+ g_ptr_array_free(oc_argv, TRUE);
+
+ DBG("openconnect started with pid %d, dev %s", data->pid,
+ data->if_name);
+
+ if (write(oc_fd, vpncookie, strlen(vpncookie)) != strlen(vpncookie) ||
+ write(oc_fd, "\n", 1) != 1) {
+ connman_error("openconnect failed to take cookie on stdin");
+ kill(data->pid, SIGKILL);
+ kill_tun(data->if_name);
+ return -EIO;
+ }
+ close(oc_fd);
+
+ connman_network_ref(network);
+ oc_watch = g_child_watch_source_new(data->pid);
+ g_source_set_callback(oc_watch, (GSourceFunc)oc_watch_cb,
+ network, NULL);
+ g_source_attach(oc_watch, NULL);
+ g_source_unref(oc_watch);
+
+ connman_device_add_network(device, network);
+ return 0;
+}
+
+static int oc_dev_disable(struct connman_device *device)
+{
+ DBG("");
+
+ return 0;
+}
+
+static struct connman_device_driver device_driver = {
+ .name = "openconnect",
+ .type = CONNMAN_DEVICE_TYPE_VPN,
+ .probe = oc_dev_probe,
+ .remove = oc_dev_remove,
+ .enable = oc_dev_enable,
+ .disable = oc_dev_disable,
+ .join = oc_dev_join,
+};
+
+static struct connman_device *create_device(const char *name)
+{
+ struct connman_device *device;
+
+ device = connman_device_create(name, CONNMAN_DEVICE_TYPE_VPN);
+ if (device == NULL)
+ return;
+
+ connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_SINGLE);
+ connman_device_register(device);
+ return device;
+}
+
+static int oc_net_probe(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ /* These networks should only come from oc_dev_join() */
+ if (!connman_network_get_data(network))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void oc_net_remove(struct connman_network *network)
+{
+ struct oc_net_data *data = connman_network_get_data(network);
+
+ DBG("network %p", network);
+
+ connman_network_set_data(network, NULL);
+ g_free(data);
+}
+
+static int oc_net_connect(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ /* Should never happen -- use JoinNetwork instead */
+ return -EINVAL;
+}
+
+static int oc_net_disconnect(struct connman_network *network)
+{
+ struct oc_net_data *data = connman_network_get_data(network);
+
+ DBG("network %p: kill pid %d", network, data);
+
+ kill(data->pid, SIGTERM);
+ return 0;
+}
+
+static struct connman_network_driver oc_net_driver = {
+ .name = "openconnect",
+ .type = CONNMAN_NETWORK_TYPE_VPN,
+ .probe = oc_net_probe,
+ .remove = oc_net_remove,
+ .connect = oc_net_connect,
+ .disconnect = oc_net_disconnect,
+};
+
+static DBusHandlerResult openconnect_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessageIter iter, dict;
+ struct dhclient_task *task;
+ struct connman_device *device = data;
+ struct connman_network *network;
+ struct connman_element *element;
+ const char *reason, *network_id, *key, *value;
+ uint32_t addr, mask, net, brd;
+
+ if (!dbus_message_is_method_call(msg, OPENCONNECT_INTF, "notify"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ dbus_message_iter_init(msg, &iter);
+
+ dbus_message_iter_get_basic(&iter, &reason);
+ dbus_message_iter_next(&iter);
+
+ dbus_message_iter_get_basic(&iter, &network_id);
+ dbus_message_iter_next(&iter);
+
+ network = connman_device_get_network(device, network_id);
+ DBG("reason %s network %s %p", reason, network_id, network);
+
+ if (!network) {
+ connman_error("No network '%s' found", network_id);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (strcmp(reason, "connect")) {
+ connman_network_set_connected(network, FALSE);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ element = connman_element_create(NULL);
+ if (!element) {
+ connman_error("Failed to allocate IPv4 element");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ element->type = CONNMAN_ELEMENT_TYPE_IPV4;
+ element->index = connman_network_get_index(network);
+ element->ipv4.method = CONNMAN_IPV4_METHOD_STATIC;
+
+ dbus_message_iter_recurse(&iter, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_get_basic(&entry, &value);
+
+ if (strcmp(key, "CISCO_CSTP_OPTIONS"))
+ DBG("%s = %s", key, value);
+
+ if (!strcmp(key, "INTERNAL_IP4_ADDRESS"))
+ element->ipv4.address = g_strdup(value);
+
+ if (!strcmp(key, "INTERNAL_IP4_NETMASK"))
+ element->ipv4.netmask = g_strdup(value);
+
+ if (!strcmp(key, "INTERNAL_IP4_DNS")) {
+ element->ipv4.nameserver = g_strdup(value);
+ /* FIXME: How do we handle more than one? */
+ if (strchr(element->ipv4.nameserver, ' '))
+ *strchr(element->ipv4.nameserver, ' ') = 0;
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (!element->ipv4.address || !element->ipv4.netmask) {
+ connman_error("Legacy IP parameters incomplete");
+ connman_element_unref(element);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ addr = ntohl(inet_addr(element->ipv4.address));
+ mask = ntohl(inet_addr(element->ipv4.netmask));
+ net = addr & mask;
+ brd = net | ~mask;
+
+ DBG("addr %x mask %x net %x brd %x", addr, mask, net, brd);
+
+ element->ipv4.network = g_strdup_printf("%d.%d.%d.%d",
+ net >> 24,
+ (net >> 16) & 0xff,
+ (net >> 8) & 0xff,
+ net & 0xff);
+ element->ipv4.broadcast = g_strdup_printf("%d.%d.%d.%d",
+ brd >> 24,
+ (brd >> 16) & 0xff,
+ (brd >> 8) & 0xff,
+ brd & 0xff);
+ DBG("%s %s %s %s",
+ element->ipv4.address, element->ipv4.netmask,
+ element->ipv4.network, element->ipv4.broadcast);
+
+ connman_network_set_connected(network,
+ !strcmp(reason, "connect"));
+
+ inet_ifup(connman_network_get_index(network));
+
+ /* Marcel, please don't hurt me! */
+ connman_element_register(element, (void *)network);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusConnection *connection;
+
+static const char *openconnect_rule = "path=" OPENCONNECT_PATH
+ ",interface=" OPENCONNECT_INTF;
+
+
+static int openconnect_init(void)
+{
+ int err;
+ struct connman_device *device;
+
+ connman_device_driver_register(&device_driver);
+ connman_network_driver_register(&oc_net_driver);
+
+ device = create_device("openconnect");
+
+ connection = connman_dbus_get_connection();
+
+ busname = dbus_bus_get_unique_name(connection);
+ DBG("busname %s", busname);
+ // busname = CONNMAN_SERVICE;
+
+ dbus_connection_add_filter(connection, openconnect_filter,
+ device, NULL);
+
+ dbus_bus_add_match(connection, openconnect_rule, NULL);
+
+ return 0;
+}
+
+static void openconnect_exit(void)
+{
+ connman_device_driver_unregister(&device_driver);
+ connman_network_driver_unregister(&oc_net_driver);
+
+ dbus_bus_remove_match(connection, openconnect_rule, NULL);
+
+ dbus_connection_remove_filter(connection, openconnect_filter, NULL);
+
+ dbus_connection_unref(connection);
+ // connman_device_unref(device);
+}
+
+CONNMAN_PLUGIN_DEFINE(openconnect, "OpenConnect VPN plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, openconnect_init,
openconnect_exit)
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index a0c6363..bc0a093 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -24,6 +24,12 @@ script_PROGRAMS += dhclient-script
dhclient_script_LDADD = @DBUS_LIBS@
endif
+if OPENCONNECT
+script_PROGRAMS += openconnect-script
+
+openconnect_script_LDADD = @DBUS_LIBS@
+endif
+
if PPPD
script_LTLIBRARIES += pppd-plugin.la
diff --git a/scripts/openconnect-script.c b/scripts/openconnect-script.c
new file mode 100644
index 0000000..029963e
--- /dev/null
+++ b/scripts/openconnect-script.c
@@ -0,0 +1,134 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+#define OPENCONNECT_INTF "org.infradead.openconnect"
+#define OPENCONNECT_PATH "/org/infradead/openconnect"
+
+extern char **environ;
+
+static void append(DBusMessageIter *dict, const char *pattern)
+{
+ DBusMessageIter entry;
+ const char *key, *value;
+ char *delim;
+
+ delim = strchr(pattern, '=');
+ *delim = '\0';
+
+ key = pattern;
+ value = delim + 1;
+
+ /* We clean the environment before invoking openconnect, but
+ might as well still filter out the few things that get
+ added that we're not interested in */
+ if (!strcmp(key, "PWD") || !strcmp(key, "_") ||
+ !strcmp(key, "SHLVL") || !strcmp(key, "connman_busname") ||
+ !strcmp(key, "connman_network"))
+ return;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *conn;
+ DBusError error;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict;
+ char **envp, *busname, *reason, *network;
+ int i;
+
+ busname = getenv("connman_busname");
+ network = getenv("connman_network");
+
+ reason = getenv("reason");
+
+ if (!busname || !network || !reason) {
+ fprintf(stderr, "Required environment variables not set\n");
+ return 1;
+ }
+ dbus_error_init(&error);
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (conn == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ fprintf(stderr, "%s\n", error.message);
+ dbus_error_free(&error);
+ } else
+ fprintf(stderr, "Failed to get on system bus\n");
+ return 0;
+ }
+
+ msg = dbus_message_new_method_call(busname, OPENCONNECT_PATH,
+ OPENCONNECT_INTF, "notify");
+ if (msg == NULL) {
+ dbus_connection_unref(conn);
+ fprintf(stderr, "Failed to allocate method call\n");
+ return 0;
+ }
+
+ dbus_message_set_no_reply(msg, TRUE);
+
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &reason,
+ DBUS_TYPE_STRING, &network,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ for (envp = environ; envp && *envp; envp++)
+ append(&dict, *envp);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (dbus_connection_send(conn, msg, NULL) == FALSE)
+ fprintf(stderr, "Failed to send message\n");
+
+ dbus_connection_flush(conn);
+
+ dbus_message_unref(msg);
+
+ dbus_connection_unref(conn);
+
+ return 0;
+}
diff --git a/src/device.c b/src/device.c
index df7e7fb..2f744df 100644
--- a/src/device.c
+++ b/src/device.c
@@ -123,6 +123,8 @@ static const char *type2string(enum connman_device_type
type)
case CONNMAN_DEVICE_TYPE_NOZOMI:
case CONNMAN_DEVICE_TYPE_NOVATEL:
return "cellular";
+ case CONNMAN_DEVICE_TYPE_VPN:
+ return "vpn";
}
return NULL;
@@ -549,6 +551,9 @@ static DBusMessage *join_network(DBusConnection *conn,
case CONNMAN_DEVICE_TYPE_WIFI:
type = CONNMAN_NETWORK_TYPE_WIFI;
break;
+ case CONNMAN_DEVICE_TYPE_VPN:
+ type = CONNMAN_NETWORK_TYPE_VPN;
+ break;
default:
return __connman_error_not_supported(msg);
}
diff --git a/test/join-vpn b/test/join-vpn
new file mode 100755
index 0000000..985b35f
--- /dev/null
+++ b/test/join-vpn
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+ print "Usage: %s <ssid> [passphrase] [security]" % (sys.argv[0])
+ sys.exit(1)
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
+ "org.moblin.connman.Manager")
+
+properties = manager.GetProperties()
+
+for path in properties["Devices"]:
+ device = dbus.Interface(bus.get_object("org.moblin.connman", path),
+ "org.moblin.connman.Device")
+
+ properties = device.GetProperties()
+
+ if (properties["Type"] != "vpn"):
+ continue;
+
+ print "[ %s ]" % (path)
+ print "Attempting to join %s" % (sys.argv[1])
+
+ device.JoinNetwork({ "OpenConnect.Host": sys.argv[1],
+ "OpenConnect.Cookie": sys.argv[2]})
--
dwmw2
_______________________________________________
connman mailing list
[email protected]
https://lists.moblin.org/mailman/listinfo/connman