---
 src/connman.h   |    2 +-
 src/manager.c   |    8 ++--
 src/tethering.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/src/connman.h b/src/connman.h
index e3bccbe..834896c 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -445,7 +445,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/manager.c b/src/manager.c
index 0514655..f73330c 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 00fa3de..9ab90e0 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"
 
@@ -56,6 +59,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 +385,65 @@ void __connman_tethering_update_interface(const char 
*interface)
        enable_nat(interface);
 }
 
+static int create_tun_interface(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;
+}
+
+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 +459,52 @@ 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 = create_tun_interface(&iface);
+       if (fd < 0)
+               return fd;
+
+       index = connman_inet_ifindex(iface);
+       if (index < 0) {
+               err = -ENODEV;
+               goto error;
+       }
+       DBG("inteface %s", iface);
+
        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)
-- 
1.7.4.1

_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to