]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/net/tun.c
virtio-net: restore VIRTIO_HDR_F_DATA_VALID on receiving
[mirror_ubuntu-bionic-kernel.git] / drivers / net / tun.c
index db6acecabeaa3f51344ffc366ec0a502da4fea08..2cd10b26b65012ab882c67a433946dadda83b8f7 100644 (file)
@@ -73,7 +73,7 @@
 #include <linux/uio.h>
 #include <linux/skb_array.h>
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 /* Uncomment to enable debugging */
 /* #define TUN_DEBUG 1 */
@@ -878,13 +878,6 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
            sk_filter(tfile->socket.sk, skb))
                goto drop;
 
-       /* Limit the number of packets queued by dividing txq length with the
-        * number of queues.
-        */
-       if (skb_queue_len(&tfile->socket.sk->sk_receive_queue) * numqueues
-                         >= dev->tx_queue_len)
-               goto drop;
-
        if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
                goto drop;
 
@@ -925,18 +918,6 @@ static void tun_net_mclist(struct net_device *dev)
         */
 }
 
-#define MIN_MTU 68
-#define MAX_MTU 65535
-
-static int
-tun_net_change_mtu(struct net_device *dev, int new_mtu)
-{
-       if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU)
-               return -EINVAL;
-       dev->mtu = new_mtu;
-       return 0;
-}
-
 static netdev_features_t tun_net_fix_features(struct net_device *dev,
        netdev_features_t features)
 {
@@ -1014,7 +995,6 @@ static const struct net_device_ops tun_netdev_ops = {
        .ndo_open               = tun_net_open,
        .ndo_stop               = tun_net_close,
        .ndo_start_xmit         = tun_net_xmit,
-       .ndo_change_mtu         = tun_net_change_mtu,
        .ndo_fix_features       = tun_net_fix_features,
        .ndo_select_queue       = tun_select_queue,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1029,7 +1009,6 @@ static const struct net_device_ops tap_netdev_ops = {
        .ndo_open               = tun_net_open,
        .ndo_stop               = tun_net_close,
        .ndo_start_xmit         = tun_net_xmit,
-       .ndo_change_mtu         = tun_net_change_mtu,
        .ndo_fix_features       = tun_net_fix_features,
        .ndo_set_rx_mode        = tun_net_mclist,
        .ndo_set_mac_address    = eth_mac_addr,
@@ -1062,6 +1041,9 @@ static void tun_flow_uninit(struct tun_struct *tun)
        tun_flow_flush(tun);
 }
 
+#define MIN_MTU 68
+#define MAX_MTU 65535
+
 /* Initialize net device. */
 static void tun_net_init(struct net_device *dev)
 {
@@ -1092,6 +1074,9 @@ static void tun_net_init(struct net_device *dev)
 
                break;
        }
+
+       dev->min_mtu = MIN_MTU;
+       dev->max_mtu = MAX_MTU - dev->hard_header_len;
 }
 
 /* Character device part */
@@ -1171,7 +1156,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        bool zerocopy = false;
        int err;
        u32 rxhash;
-       ssize_t n;
 
        if (!(tun->dev->flags & IFF_UP))
                return -EIO;
@@ -1181,8 +1165,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                        return -EINVAL;
                len -= sizeof(pi);
 
-               n = copy_from_iter(&pi, sizeof(pi), from);
-               if (n != sizeof(pi))
+               if (!copy_from_iter_full(&pi, sizeof(pi), from))
                        return -EFAULT;
        }
 
@@ -1191,8 +1174,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                        return -EINVAL;
                len -= tun->vnet_hdr_sz;
 
-               n = copy_from_iter(&gso, sizeof(gso), from);
-               if (n != sizeof(gso))
+               if (!copy_from_iter_full(&gso, sizeof(gso), from))
                        return -EFAULT;
 
                if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
@@ -1255,8 +1237,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                return -EFAULT;
        }
 
-       err = virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun));
-       if (err) {
+       if (virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun))) {
                this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
                kfree_skb(skb);
                return -EINVAL;
@@ -1302,7 +1283,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        skb_probe_transport_header(skb, 0);
 
        rxhash = skb_get_hash(skb);
+#ifndef CONFIG_4KSTACKS
+       local_bh_disable();
+       netif_receive_skb(skb);
+       local_bh_enable();
+#else
        netif_rx_ni(skb);
+#endif
 
        stats = get_cpu_ptr(tun->pcpu_stats);
        u64_stats_update_begin(&stats->syncp);
@@ -1367,15 +1354,13 @@ static ssize_t tun_put_user(struct tun_struct *tun,
        }
 
        if (vnet_hdr_sz) {
-               struct virtio_net_hdr gso = { 0 }; /* no info leak */
-               int ret;
+               struct virtio_net_hdr gso;
 
                if (iov_iter_count(iter) < vnet_hdr_sz)
                        return -EINVAL;
 
-               ret = virtio_net_hdr_from_skb(skb, &gso,
-                                             tun_is_little_endian(tun));
-               if (ret) {
+               if (virtio_net_hdr_from_skb(skb, &gso,
+                                           tun_is_little_endian(tun), true)) {
                        struct skb_shared_info *sinfo = skb_shinfo(skb);
                        pr_err("unexpected GSO type: "
                               "0x%x, gso_size %d, hdr_len %d\n",
@@ -1991,7 +1976,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        int le;
        int ret;
 
-       if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) {
+       if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == SOCK_IOC_TYPE) {
                if (copy_from_user(&ifr, argp, ifreq_len))
                        return -EFAULT;
        } else {
@@ -2011,7 +1996,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        rtnl_lock();
 
        tun = __tun_get(tfile);
-       if (cmd == TUNSETIFF && !tun) {
+       if (cmd == TUNSETIFF) {
+               ret = -EEXIST;
+               if (tun)
+                       goto unlock;
+
                ifr.ifr_name[IFNAMSIZ-1] = '\0';
 
                ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr);