netdev: bfin_mac: deduce Ethernet FCS from hardware IP payload checksum
[safe/jmp/linux-2.6] / drivers / net / tun.c
index e525a6c..01b5cfc 100644 (file)
@@ -110,6 +110,9 @@ struct tun_struct {
        struct tap_filter       txflt;
        struct socket           socket;
        struct socket_wq        wq;
+
+       int                     vnet_hdr_sz;
+
 #ifdef TUN_DEBUG
        int debug;
 #endif
@@ -393,7 +396,6 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Enqueue packet */
        skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb);
-       dev->trans_start = jiffies;
 
        /* Notify and wake up reader process */
        if (tun->flags & TUN_FASYNC)
@@ -415,7 +417,6 @@ static void tun_net_mclist(struct net_device *dev)
         * _rx_ path and has nothing to do with the _tx_ path.
         * In rx path we always accept everything userspace gives us.
         */
-       return;
 }
 
 #define MIN_MTU 68
@@ -563,7 +564,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
        }
 
        if (tun->flags & TUN_VNET_HDR) {
-               if ((len -= sizeof(gso)) > count)
+               if ((len -= tun->vnet_hdr_sz) > count)
                        return -EINVAL;
 
                if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso)))
@@ -575,7 +576,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
 
                if (gso.hdr_len > len)
                        return -EINVAL;
-               offset += sizeof(gso);
+               offset += tun->vnet_hdr_sz;
        }
 
        if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
@@ -718,7 +719,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
 
        if (tun->flags & TUN_VNET_HDR) {
                struct virtio_net_hdr gso = { 0 }; /* no info leak */
-               if ((len -= sizeof(gso)) < 0)
+               if ((len -= tun->vnet_hdr_sz) < 0)
                        return -EINVAL;
 
                if (skb_is_gso(skb)) {
@@ -749,7 +750,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
                if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
                                               sizeof(gso))))
                        return -EFAULT;
-               total += sizeof(gso);
+               total += tun->vnet_hdr_sz;
        }
 
        len = min_t(int, skb->len, len);
@@ -1035,6 +1036,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun->dev = dev;
                tun->flags = flags;
                tun->txflt.count = 0;
+               tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
 
                err = -ENOMEM;
                sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
@@ -1177,6 +1179,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        struct sock_fprog fprog;
        struct ifreq ifr;
        int sndbuf;
+       int vnet_hdr_sz;
        int ret;
 
        if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
@@ -1322,6 +1325,25 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                tun->socket.sk->sk_sndbuf = sndbuf;
                break;
 
+       case TUNGETVNETHDRSZ:
+               vnet_hdr_sz = tun->vnet_hdr_sz;
+               if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz)))
+                       ret = -EFAULT;
+               break;
+
+       case TUNSETVNETHDRSZ:
+               if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               tun->vnet_hdr_sz = vnet_hdr_sz;
+               break;
+
        case TUNATTACHFILTER:
                /* Can be set only for TAPs */
                ret = -EINVAL;