summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2011-04-20 14:41:20 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2011-04-20 15:18:57 +0200
commit86f7f6daaa4d05428e73ba5417bd0a5b4970ed32 (patch)
tree179afff495c146a6e01d9ffe00e37c7d4bc9e35d /src
parent55e275762c011595ed1d106bbb3867be415a8a07 (diff)
downloadconnman-86f7f6daaa4d05428e73ba5417bd0a5b4970ed32.tar.gz
connman-86f7f6daaa4d05428e73ba5417bd0a5b4970ed32.tar.bz2
connman-86f7f6daaa4d05428e73ba5417bd0a5b4970ed32.zip
tethering: Add support to create private networks TUN interface
Diffstat (limited to 'src')
-rw-r--r--src/connman.h2
-rw-r--r--src/inet.c36
-rw-r--r--src/manager.c8
-rw-r--r--src/tethering.c61
4 files changed, 99 insertions, 8 deletions
diff --git a/src/connman.h b/src/connman.h
index ab2b52e6..b79726fd 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -456,7 +456,7 @@ void __connman_tethering_update_interface(const char *interface);
void __connman_tethering_set_enabled(void);
void __connman_tethering_set_disabled(void);
-int __connman_private_network_request(const char *owner);
+int __connman_private_network_request(DBusMessage *msg, const char *owner);
int __connman_private_network_release(const char *owner);
#include <connman/provider.h>
diff --git a/src/inet.c b/src/inet.c
index 5e5d9cc8..ec2dc520 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -40,6 +40,8 @@
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/icmp6.h>
+#include <fcntl.h>
+#include <linux/if_tun.h>
#include "connman.h"
@@ -1265,6 +1267,40 @@ done:
return err;
}
+int connman_inet_create_tunnel(char **iface)
+{
+ struct ifreq ifr;
+ int i, fd;
+
+ 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, "tun%d", i);
+
+ if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
+ break;
+ }
+
+ if (i == 256) {
+ connman_error("Failed to find available tun device");
+ close(fd);
+ return -ENODEV;
+ }
+
+ *iface = g_strdup(ifr.ifr_name);
+
+ return fd;
+}
+
struct rs_cb_data {
GIOChannel *channel;
__connman_inet_rs_cb_t callback;
diff --git a/src/manager.c b/src/manager.c
index 05146555..f73330c2 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -601,11 +601,11 @@ static DBusMessage *request_private_network(DBusConnection *conn,
sender = dbus_message_get_sender(msg);
- err = __connman_private_network_request(sender);
+ err = __connman_private_network_request(msg, sender);
if (err < 0)
return __connman_error_failed(msg, -err);
- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ return NULL;
}
static DBusMessage *release_private_network(DBusConnection *conn,
@@ -649,8 +649,8 @@ static GDBusMethodTable manager_methods[] = {
{ "UnregisterCounter", "o", "", unregister_counter },
{ "CreateSession", "a{sv}o", "o", create_session },
{ "DestroySession", "o", "", destroy_session },
- { "RequestPrivateNetwork", "", "",
- request_private_network },
+ { "RequestPrivateNetwork", "", "h", request_private_network,
+ G_DBUS_METHOD_FLAG_ASYNC },
{ "ReleasePrivateNetwork", "", "",
release_private_network },
{ },
diff --git a/src/tethering.c b/src/tethering.c
index 00fa3dee..c8ec981a 100644
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -30,6 +30,9 @@
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/sockios.h>
+#include <string.h>
+#include <fcntl.h>
+#include <linux/if_tun.h>
#include "connman.h"
@@ -47,6 +50,8 @@
#define BRIDGE_IP_END "192.168.218.200"
#define BRIDGE_DNS "8.8.8.8"
+#define DEFAULT_MTU 1500
+
static char *default_interface = NULL;
static volatile gint tethering_enabled;
static GDHCPServer *tethering_dhcp_server = NULL;
@@ -56,6 +61,11 @@ static GHashTable *pn_hash;
struct connman_private_network {
char *owner;
guint watch;
+ DBusMessage *msg;
+ int fd;
+ char *interface;
+ int index;
+ guint iface_watch;
};
const char *__connman_tethering_get_bridge(void)
@@ -377,15 +387,31 @@ void __connman_tethering_update_interface(const char *interface)
enable_nat(interface);
}
+static void setup_tun_interface(unsigned int flags, unsigned change,
+ void *data)
+{
+ struct connman_private_network *pn = data;
+
+ DBG("index %d flags %d change %d", pn->index, flags, change);
+
+ g_dbus_send_reply(connection, pn->msg, DBUS_TYPE_UNIX_FD, &pn->fd,
+ DBUS_TYPE_INVALID);
+}
+
static void remove_private_network(gpointer user_data)
{
struct connman_private_network *pn = user_data;
+ close(pn->fd);
+
+ connman_rtnl_remove_watch(pn->iface_watch);
+
if (pn->watch > 0) {
g_dbus_remove_watch(connection, pn->watch);
pn->watch = 0;
}
+ g_free(pn->interface);
g_free(pn->owner);
g_free(pn);
}
@@ -401,25 +427,54 @@ static void owner_disconnect(DBusConnection *connection, void *user_data)
g_hash_table_remove(pn_hash, pn->owner);
}
-int __connman_private_network_request(const char *owner)
+int __connman_private_network_request(DBusMessage *msg, const char *owner)
{
struct connman_private_network *pn;
+ char *iface = NULL;
+ int index, fd, err;
pn = g_hash_table_lookup(pn_hash, owner);
if (pn != NULL)
return -EEXIST;
+ fd = connman_inet_create_tunnel(&iface);
+ if (fd < 0)
+ return fd;
+
+ index = connman_inet_ifindex(iface);
+ if (index < 0) {
+ err = -ENODEV;
+ goto error;
+ }
+ DBG("inteface %s", iface);
+
+ err = connman_inet_set_mtu(index, DEFAULT_MTU);
+
pn = g_try_new0(struct connman_private_network, 1);
- if (pn == NULL)
- return -ENOMEM;
+ if (pn == NULL) {
+ err = -ENOMEM;
+ goto error;
+ }
pn->owner = g_strdup(owner);
pn->watch = g_dbus_add_disconnect_watch(connection, pn->owner,
owner_disconnect, pn, NULL);
+ pn->msg = msg;
+ pn->fd = fd;
+ pn->interface = iface;
+ pn->index = index;
+
+ pn->iface_watch = connman_rtnl_add_newlink_watch(index,
+ setup_tun_interface, pn);
g_hash_table_insert(pn_hash, pn->owner, pn);
return 0;
+
+error:
+ close(fd);
+ g_free(iface);
+ return err;
}
int __connman_private_network_release(const char *owner)