]> Pileus Git - ~andy/linux/blobdiff - drivers/net/tun.c
tuntap: set transport header before passing it to kernel
[~andy/linux] / drivers / net / tun.c
index 2c6a22e278ea15843b7fb4500749304aad0a1444..48cd73a2dc5506afa26d41dac57721205ae0e48e 100644 (file)
@@ -70,6 +70,7 @@
 #include <net/sock.h>
 
 #include <asm/uaccess.h>
+#include <net/flow_keys.h>
 
 /* Uncomment to enable debugging */
 /* #define TUN_DEBUG 1 */
@@ -409,14 +410,12 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
 {
        struct tun_file *ntfile;
        struct tun_struct *tun;
-       struct net_device *dev;
 
        tun = rtnl_dereference(tfile->tun);
 
        if (tun && !tfile->detached) {
                u16 index = tfile->queue_index;
                BUG_ON(index >= tun->numqueues);
-               dev = tun->dev;
 
                rcu_assign_pointer(tun->tfiles[index],
                                   tun->tfiles[tun->numqueues - 1]);
@@ -747,6 +746,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
                goto drop;
        skb_orphan(skb);
 
+       nf_reset(skb);
+
        /* Enqueue packet */
        skb_queue_tail(&tfile->socket.sk->sk_receive_queue, skb);
 
@@ -1049,6 +1050,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        bool zerocopy = false;
        int err;
        u32 rxhash;
+       struct flow_keys keys;
 
        if (!(tun->flags & TUN_NO_PI)) {
                if ((len -= sizeof(pi)) > total_len)
@@ -1203,6 +1205,14 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        }
 
        skb_reset_network_header(skb);
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               skb_set_transport_header(skb, skb_checksum_start_offset(skb));
+       else if (skb_flow_dissect(skb, &keys))
+               skb_set_transport_header(skb, keys.thoff);
+       else
+               skb_reset_transport_header(skb);
+
        rxhash = skb_get_rxhash(skb);
        netif_rx_ni(skb);