Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / net / tun.c
index 4326520..6ad6fe7 100644 (file)
@@ -109,6 +109,9 @@ struct tun_struct {
 
        struct tap_filter       txflt;
        struct socket           socket;
+       struct socket_wq        wq;
+
+       int                     vnet_hdr_sz;
 
 #ifdef TUN_DEBUG
        int debug;
@@ -323,7 +326,7 @@ static void tun_net_uninit(struct net_device *dev)
        /* Inform the methods they need to stop using the dev.
         */
        if (tfile) {
-               wake_up_all(&tun->socket.wait);
+               wake_up_all(&tun->wq.wait);
                if (atomic_dec_and_test(&tfile->count))
                        __tun_detach(tun);
        }
@@ -393,12 +396,11 @@ 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)
                kill_fasync(&tun->fasync, SIGIO, POLL_IN);
-       wake_up_interruptible_poll(&tun->socket.wait, POLLIN |
+       wake_up_interruptible_poll(&tun->wq.wait, POLLIN |
                                   POLLRDNORM | POLLRDBAND);
        return NETDEV_TX_OK;
 
@@ -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
@@ -498,7 +499,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 
        DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
 
-       poll_wait(file, &tun->socket.wait, wait);
+       poll_wait(file, &tun->wq.wait, wait);
 
        if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
@@ -525,6 +526,8 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
        struct sk_buff *skb;
        int err;
 
+       sock_update_classid(sk);
+
        /* Under a page?  Don't bother with paged skb. */
        if (prepad + len < PAGE_SIZE || !linear)
                linear = len;
@@ -563,7 +566,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 +578,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 +721,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 +752,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);
@@ -773,7 +776,7 @@ static ssize_t tun_do_read(struct tun_struct *tun,
 
        DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
 
-       add_wait_queue(&tun->socket.wait, &wait);
+       add_wait_queue(&tun->wq.wait, &wait);
        while (len) {
                current->state = TASK_INTERRUPTIBLE;
 
@@ -804,7 +807,7 @@ static ssize_t tun_do_read(struct tun_struct *tun,
        }
 
        current->state = TASK_RUNNING;
-       remove_wait_queue(&tun->socket.wait, &wait);
+       remove_wait_queue(&tun->wq.wait, &wait);
 
        return ret;
 }
@@ -861,6 +864,7 @@ static struct rtnl_link_ops tun_link_ops __read_mostly = {
 static void tun_sock_write_space(struct sock *sk)
 {
        struct tun_struct *tun;
+       wait_queue_head_t *wqueue;
 
        if (!sock_writeable(sk))
                return;
@@ -868,8 +872,9 @@ static void tun_sock_write_space(struct sock *sk)
        if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
                return;
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+       wqueue = sk_sleep(sk);
+       if (wqueue && waitqueue_active(wqueue))
+               wake_up_interruptible_sync_poll(wqueue, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
 
        tun = tun_sk(sk)->tun;
@@ -1033,13 +1038,15 @@ 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);
                if (!sk)
                        goto err_free_dev;
 
-               init_waitqueue_head(&tun->socket.wait);
+               tun->socket.wq = &tun->wq;
+               init_waitqueue_head(&tun->wq.wait);
                tun->socket.ops = &tun_socket_ops;
                sock_init_data(&tun->socket, sk);
                sk->sk_write_space = tun_sock_write_space;
@@ -1174,6 +1181,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)
@@ -1319,6 +1327,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;
@@ -1342,7 +1369,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        default:
                ret = -EINVAL;
                break;
-       };
+       }
 
 unlock:
        rtnl_unlock();
@@ -1624,3 +1651,4 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(TUN_MINOR);
+MODULE_ALIAS("devname:net/tun");