summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--quicktun.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/quicktun.c b/quicktun.c
index 9d1f722..e745eb1 100644
--- a/quicktun.c
+++ b/quicktun.c
@@ -1,7 +1,9 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_arp.h>
+#include <linux/ip.h>
#include <linux/netdevice.h>
+#include <linux/udp.h>
#include <net/genetlink.h>
#include <net/sock.h>
@@ -12,8 +14,6 @@
#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
@@ -55,9 +55,32 @@ static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev
kernel_sendmsg(tun->sock, &msg, &vec, 1, skb->len);
}
+ consume_skb(skb);
+
return NETDEV_TX_OK;
}
+static void quicktun_udp_data_ready(struct sock *sk, int bytes)
+{
+ int err;
+ struct sk_buff *skb;
+ struct quicktun_struct *tun = sk->sk_user_data;
+
+ skb = skb_recv_datagram(sk, 0, 1, &err);
+ if (!skb) {
+ if (err == -EAGAIN)
+ return;
+ pr_info("Quicktun: UDP socket error %d", err);
+ return;
+ }
+
+ skb_orphan(skb);
+
+ skb_pull(skb, sizeof(struct udphdr));
+ skb->protocol = eth_type_trans(skb, tun->dev);
+ netif_rx_ni(skb);
+}
+
static int
quicktun_net_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -168,6 +191,9 @@ static int quicktun_socket_init(struct net_device *dev)
if (err < 0)
return err;
+ tun->sock->sk->sk_data_ready = quicktun_udp_data_ready;
+ tun->sock->sk->sk_user_data = tun;
+
err = kernel_bind(tun->sock, (struct sockaddr*)&tun->local_address, sizeof(tun->local_address));
if (err < 0)
goto error;
@@ -243,6 +269,8 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf
if (err < 0)
goto err_free_dev;
+ rtnl_lock();
+
if (strchr(dev->name, '%')) {
err = dev_alloc_name(dev, dev->name);
if (err < 0)
@@ -253,9 +281,14 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf
if (err < 0)
goto err_free_sk;
+ rtnl_unlock();
+
return 0;
err_free_sk:
+ rtnl_unlock();
+ sock_release(tun->sock);
+
err_free_dev:
free_netdev(dev);
return err;