summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2011-04-12 21:03:35 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2011-04-12 21:03:35 +0200
commit35bfd16af8f8316de5ee392fe06020a7d7ed7a33 (patch)
treea91818cbe150d002f995b0e2ffefd58a55931cf5
downloadmodquicktun-35bfd16af8f8316de5ee392fe06020a7d7ed7a33.tar
modquicktun-35bfd16af8f8316de5ee392fe06020a7d7ed7a33.zip
Sending through the quicktun interface is working now.
-rw-r--r--.gitignore9
-rw-r--r--Makefile19
-rw-r--r--qtctl.c36
-rw-r--r--quicktun.c321
-rw-r--r--quicktun.h33
5 files changed, 418 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8b3e06b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+.*
+*~
+Module.symvers
+modules.order
+qtctl
+*.o
+*.ko
+*.mod.c
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a26b6e8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+ifneq ($(KERNELRELEASE),)
+obj-m := quicktun.o
+
+else
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+all: qtctl
+ $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+
+qtctl: qtctl.c quicktun.h
+ cc -o qtctl qtctl.c -lnl
+endif
+
+
+.PHONY: clean
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.markers *.symvers *.order
diff --git a/qtctl.c b/qtctl.c
new file mode 100644
index 0000000..e601ad9
--- /dev/null
+++ b/qtctl.c
@@ -0,0 +1,36 @@
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "quicktun.h"
+
+
+int main()
+{
+ struct nl_handle *sock;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ int family;
+
+ sock = nl_handle_alloc();
+ genl_connect(sock);
+ family = genl_ctrl_resolve(sock, "quicktun");
+
+ msg = nlmsg_alloc();
+ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, QUICKTUN_CMD_CREATE_DEVICE, 1);
+ nla_put_u16(msg, QUICKTUN_A_TYPE, QUICKTUN_TAP_DEV);
+ nla_put_u32(msg, QUICKTUN_A_REMOTE_ADDRESS, ntohl(inet_addr("192.168.0.2")));
+
+ nl_send_auto_complete(sock, msg);
+
+ nlmsg_free(msg);
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL);
+
+ nl_recvmsgs(sock, cb);
+
+ return 0;
+}
diff --git a/quicktun.c b/quicktun.c
new file mode 100644
index 0000000..9d1f722
--- /dev/null
+++ b/quicktun.c
@@ -0,0 +1,321 @@
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+#include <net/sock.h>
+
+#include "quicktun.h"
+
+
+#define DRV_NAME "quicktun"
+#define DRV_VERSION "0.1"
+#define DRV_DESCRIPTION "Quicktun tunnel driver"
+
+#define QUICKTUN_READQ_SIZE 500
+
+#define QUICKTUN_TYPE_MASK 0x000f
+#define QUICKTUN_FLAG_REMOTE_FLOAT 0x0010
+
+#define MIN_MTU 68
+#define MAX_MTU 65535
+
+
+struct quicktun_struct {
+ struct net_device *dev;
+ unsigned long flags;
+
+ struct sockaddr_in local_address;
+ struct sockaddr_in remote_address;
+
+ struct socket *sock;
+};
+
+
+static void quicktun_net_uninit(struct net_device *dev)
+{
+}
+
+static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct quicktun_struct *tun = netdev_priv(dev);
+ struct msghdr msg;
+ struct kvec vec;
+
+ if (tun->remote_address.sin_addr.s_addr) {
+ vec.iov_base = skb->data;
+ vec.iov_len = skb->len;
+
+ msg.msg_name = &tun->remote_address;
+ msg.msg_namelen = sizeof(tun->remote_address);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_DONTWAIT;
+
+ kernel_sendmsg(tun->sock, &msg, &vec, 1, skb->len);
+ }
+
+ return NETDEV_TX_OK;
+}
+
+static int
+quicktun_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+static const struct net_device_ops quicktun_tun_netdev_ops = {
+ .ndo_uninit = quicktun_net_uninit,
+ .ndo_start_xmit = quicktun_net_xmit,
+ .ndo_change_mtu = quicktun_net_change_mtu,
+};
+
+static const struct net_device_ops quicktun_tap_netdev_ops = {
+ .ndo_uninit = quicktun_net_uninit,
+ .ndo_start_xmit = quicktun_net_xmit,
+ .ndo_change_mtu = quicktun_net_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+
+static void quicktun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct quicktun_struct *tun = netdev_priv(dev);
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+
+ switch (tun->flags & QUICKTUN_TYPE_MASK) {
+ case QUICKTUN_TUN_DEV:
+ strcpy(info->bus_info, "tun");
+ break;
+ case QUICKTUN_TAP_DEV:
+ strcpy(info->bus_info, "tap");
+ break;
+ }
+}
+
+static u32 quicktun_always_on(struct net_device *dev)
+{
+ return 1;
+}
+
+
+static const struct ethtool_ops quicktun_ethtool_ops = {
+ .get_drvinfo = quicktun_get_drvinfo,
+ .get_link = quicktun_always_on,
+};
+
+
+static void quicktun_free_netdev(struct net_device *dev)
+{
+}
+
+static void quicktun_setup(struct net_device *dev)
+{
+ struct quicktun_struct *tun = netdev_priv(dev);
+
+ tun->local_address.sin_family = AF_INET;
+ tun->local_address.sin_addr.s_addr = 0;
+ tun->local_address.sin_port = htons(QUICKTUN_DEFAULT_PORT);
+ tun->remote_address.sin_family = AF_INET;
+ tun->remote_address.sin_addr.s_addr = 0;
+ tun->remote_address.sin_port = htons(QUICKTUN_DEFAULT_PORT);
+
+ dev->ethtool_ops = &quicktun_ethtool_ops;
+ dev->destructor = quicktun_free_netdev;
+}
+
+static void quicktun_net_init(struct net_device *dev)
+{
+ struct quicktun_struct *tun = netdev_priv(dev);
+
+ switch (tun->flags & QUICKTUN_TYPE_MASK) {
+ case QUICKTUN_TUN_DEV:
+ dev->netdev_ops = &quicktun_tun_netdev_ops;
+
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->mtu = 1500;
+
+ dev->type = ARPHRD_NONE;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+ break;
+
+ case QUICKTUN_TAP_DEV:
+ dev->netdev_ops = &quicktun_tap_netdev_ops;
+
+ ether_setup(dev);
+
+ random_ether_addr(dev->dev_addr);
+ break;
+ }
+}
+
+static int quicktun_socket_init(struct net_device *dev)
+{
+ int err;
+ struct quicktun_struct *tun = netdev_priv(dev);
+
+
+ err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &tun->sock);
+ if (err < 0)
+ return err;
+
+ err = kernel_bind(tun->sock, (struct sockaddr*)&tun->local_address, sizeof(tun->local_address));
+ if (err < 0)
+ goto error;
+
+ return 0;
+ error:
+ sock_release(tun->sock);
+ return err;
+}
+
+static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *info)
+{
+ unsigned long flags = 0;
+ __u16 type = 0;
+ struct quicktun_struct *tun;
+ struct net *net = genl_info_net(info);
+ struct net_device *dev;
+ char *name = "qt%d";
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (info->attrs[QUICKTUN_A_TYPE])
+ type = nla_get_u16(info->attrs[QUICKTUN_A_TYPE]);
+
+ switch (type) {
+ case QUICKTUN_TUN_DEV:
+ case QUICKTUN_TAP_DEV:
+ flags |= type;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (info->attrs[QUICKTUN_A_IFNAME])
+ name = nla_data(info->attrs[QUICKTUN_A_IFNAME]);
+
+ dev = alloc_netdev(sizeof(struct quicktun_struct), name, quicktun_setup);
+
+ if (!dev)
+ return -ENOMEM;
+
+ dev_net_set(dev, net);
+
+ tun = netdev_priv(dev);
+ tun->dev = dev;
+ tun->flags = flags;
+
+ quicktun_net_init(dev);
+
+ if (info->attrs[QUICKTUN_A_LOCAL_ADDRESS])
+ tun->local_address.sin_addr.s_addr = htonl(nla_get_u32(info->attrs[QUICKTUN_A_LOCAL_ADDRESS]));
+
+ /* Set remote port to local port by default */
+ if (info->attrs[QUICKTUN_A_LOCAL_PORT])
+ tun->remote_address.sin_port = tun->local_address.sin_port = htons(nla_get_u16(info->attrs[QUICKTUN_A_LOCAL_PORT]));
+
+ if (info->attrs[QUICKTUN_A_REMOTE_ADDRESS])
+ tun->remote_address.sin_addr.s_addr = htonl(nla_get_u32(info->attrs[QUICKTUN_A_REMOTE_ADDRESS]));
+
+ if (info->attrs[QUICKTUN_A_REMOTE_PORT])
+ tun->remote_address.sin_port = htons(nla_get_u16(info->attrs[QUICKTUN_A_REMOTE_PORT]));
+
+ if (info->attrs[QUICKTUN_A_REMOTE_FLOAT]) {
+ if(nla_get_flag(info->attrs[QUICKTUN_A_REMOTE_FLOAT]))
+ tun->flags |= QUICKTUN_FLAG_REMOTE_FLOAT;
+ else
+ tun->flags &= ~QUICKTUN_FLAG_REMOTE_FLOAT;
+ }
+
+ err = quicktun_socket_init(dev);
+ if (err < 0)
+ goto err_free_dev;
+
+ if (strchr(dev->name, '%')) {
+ err = dev_alloc_name(dev, dev->name);
+ if (err < 0)
+ goto err_free_sk;
+ }
+
+ err = register_netdevice(tun->dev);
+ if (err < 0)
+ goto err_free_sk;
+
+ return 0;
+
+ err_free_sk:
+ err_free_dev:
+ free_netdev(dev);
+ return err;
+}
+
+static int quicktun_cmd_destroy_device(struct sk_buff *skb, struct genl_info *info)
+{
+ return 0;
+}
+
+
+static struct genl_family quicktun_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = DRV_NAME,
+ .version = 1,
+ .hdrsize = 0,
+ .maxattr = QUICKTUN_A_MAX,
+};
+
+
+static struct nla_policy quicktun_nl_policy[__QUICKTUN_A_MAX] = {
+ [QUICKTUN_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
+ [QUICKTUN_A_TYPE] = { .type = NLA_U16 },
+ [QUICKTUN_A_LOCAL_ADDRESS] = { .type = NLA_U32 },
+ [QUICKTUN_A_LOCAL_PORT] = { .type = NLA_U16 },
+ [QUICKTUN_A_REMOTE_ADDRESS] = { .type = NLA_U32 },
+ [QUICKTUN_A_REMOTE_PORT] = { .type = NLA_U16 },
+ [QUICKTUN_A_REMOTE_FLOAT] = { .type = NLA_FLAG },
+};
+
+static struct genl_ops quicktun_nl_ops[] = {
+ {
+ .cmd = QUICKTUN_CMD_CREATE_DEVICE,
+ .doit = quicktun_cmd_create_device,
+ .policy = quicktun_nl_policy,
+ },
+ {
+ .cmd = QUICKTUN_CMD_DESTROY_DEVICE,
+ .doit = quicktun_cmd_destroy_device,
+ .policy = quicktun_nl_policy,
+ },
+};
+
+static int __init quicktun_init(void)
+{
+ int ret = 0;
+
+ pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+
+ ret = genl_register_family_with_ops(&quicktun_nl_family, quicktun_nl_ops, ARRAY_SIZE(quicktun_nl_ops));
+ return ret;
+}
+
+static void quicktun_exit(void)
+{
+ genl_unregister_family(&quicktun_nl_family);
+}
+
+
+module_init(quicktun_init);
+module_exit(quicktun_exit);
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_LICENSE("GPL");
diff --git a/quicktun.h b/quicktun.h
new file mode 100644
index 0000000..a363491
--- /dev/null
+++ b/quicktun.h
@@ -0,0 +1,33 @@
+#ifndef __QUICKTUN_H
+#define __QUICKTUN_H
+
+#define QUICKTUN_TUN_DEV 0x0001
+#define QUICKTUN_TAP_DEV 0x0002
+
+enum {
+ QUICKTUN_CMD_UNSPEC,
+ QUICKTUN_CMD_CREATE_DEVICE,
+ QUICKTUN_CMD_MODIFY_DEVICE,
+ QUICKTUN_CMD_DESTROY_DEVICE,
+ QUICKTUN_CMD_GET_DEVICE,
+ __QUICKTUN_CMD_MAX
+};
+
+enum {
+ QUICKTUN_A_UNSPEC,
+ QUICKTUN_A_IFNAME,
+ QUICKTUN_A_TYPE,
+ QUICKTUN_A_LOCAL_ADDRESS,
+ QUICKTUN_A_LOCAL_PORT,
+ QUICKTUN_A_REMOTE_ADDRESS,
+ QUICKTUN_A_REMOTE_PORT,
+ QUICKTUN_A_REMOTE_FLOAT,
+ __QUICKTUN_A_MAX
+};
+
+#define QUICKTUN_CMD_MAX (__QUICKTUN_CMD_MAX - 1)
+#define QUICKTUN_A_MAX (__QUICKTUN_A_MAX - 1)
+
+#define QUICKTUN_DEFAULT_PORT 2998
+
+#endif /* __QUICKTUN_H */