Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / net / tun.c
index a5cbf67..c0df872 100644 (file)
@@ -110,9 +110,11 @@ do {                                                               \
  * overload it to mean fasync when stored there.
  */
 #define TUN_FASYNC     IFF_ATTACH_QUEUE
+/* High bits in flags field are unused. */
+#define TUN_VNET_LE     0x80000000
 
 #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
-                     IFF_VNET_LE | IFF_MULTI_QUEUE)
+                     IFF_MULTI_QUEUE)
 #define GOODCOPY_LEN 128
 
 #define FLT_EXACT_COUNT 8
@@ -208,12 +210,12 @@ struct tun_struct {
 
 static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
 {
-       return __virtio16_to_cpu(tun->flags & IFF_VNET_LE, val);
+       return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val);
 }
 
 static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val)
 {
-       return __cpu_to_virtio16(tun->flags & IFF_VNET_LE, val);
+       return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val);
 }
 
 static inline u32 tun_hashfn(u32 rxhash)
@@ -1378,7 +1380,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
        skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
                                  &peeked, &off, &err);
        if (!skb)
-               return 0;
+               return err;
 
        ret = tun_put_user(tun, tfile, skb, to);
        if (unlikely(ret < 0))
@@ -1499,7 +1501,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
        }
        ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT);
-       if (ret > total_len) {
+       if (ret > (ssize_t)total_len) {
                m->msg_flags |= MSG_TRUNC;
                ret = flags & MSG_TRUNC ? ret : total_len;
        }
@@ -1843,6 +1845,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        int sndbuf;
        int vnet_hdr_sz;
        unsigned int ifindex;
+       int le;
        int ret;
 
        if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) {
@@ -2042,6 +2045,23 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                tun->vnet_hdr_sz = vnet_hdr_sz;
                break;
 
+       case TUNGETVNETLE:
+               le = !!(tun->flags & TUN_VNET_LE);
+               if (put_user(le, (int __user *)argp))
+                       ret = -EFAULT;
+               break;
+
+       case TUNSETVNETLE:
+               if (get_user(le, (int __user *)argp)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (le)
+                       tun->flags |= TUN_VNET_LE;
+               else
+                       tun->flags &= ~TUN_VNET_LE;
+               break;
+
        case TUNATTACHFILTER:
                /* Can be set only for TAPs */
                ret = -EINVAL;