The vnet handling code will be reused by tap.

Signed-off-by: Akihiko Odaki <akihiko.od...@daynix.com>
---
 MAINTAINERS            |   2 +-
 drivers/net/tun.c      | 179 +----------------------------------------------
 drivers/net/tun_vnet.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 187 insertions(+), 178 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 
910305c11e8a882da5b49ce5bd55011b93f28c32..bc32b7e23c79ab80b19c8207f14c5e51a47ec89f
 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23902,7 +23902,7 @@ W:      http://vtun.sourceforge.net/tun
 F:     Documentation/networking/tuntap.rst
 F:     arch/um/os-Linux/drivers/
 F:     drivers/net/tap.c
-F:     drivers/net/tun.c
+F:     drivers/net/tun*
 
 TURBOCHANNEL SUBSYSTEM
 M:     "Maciej W. Rozycki" <ma...@orcam.me.uk>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 
5bd1c21032ed673ba8e39dd5a488cce11599855b..b14231a743915c2851eaae49d757b763ec4a8841
 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -83,6 +83,8 @@
 #include <linux/uaccess.h>
 #include <linux/proc_fs.h>
 
+#include "tun_vnet.h"
+
 static void tun_default_link_ksettings(struct net_device *dev,
                                       struct ethtool_link_ksettings *cmd);
 
@@ -94,9 +96,6 @@ static void tun_default_link_ksettings(struct net_device *dev,
  * 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_VNET_BE     0x40000000
 
 #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
                      IFF_MULTI_QUEUE | IFF_NAPI | IFF_NAPI_FRAGS)
@@ -298,180 +297,6 @@ static bool tun_napi_frags_enabled(const struct tun_file 
*tfile)
        return tfile->napi_frags_enabled;
 }
 
-static inline bool tun_legacy_is_little_endian(unsigned int flags)
-{
-       return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
-                (flags & TUN_VNET_BE)) &&
-               virtio_legacy_is_little_endian();
-}
-
-static long tun_get_vnet_be(unsigned int flags, int __user *argp)
-{
-       int be = !!(flags & TUN_VNET_BE);
-
-       if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
-               return -EINVAL;
-
-       if (put_user(be, argp))
-               return -EFAULT;
-
-       return 0;
-}
-
-static long tun_set_vnet_be(unsigned int *flags, int __user *argp)
-{
-       int be;
-
-       if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
-               return -EINVAL;
-
-       if (get_user(be, argp))
-               return -EFAULT;
-
-       if (be)
-               *flags |= TUN_VNET_BE;
-       else
-               *flags &= ~TUN_VNET_BE;
-
-       return 0;
-}
-
-static inline bool tun_is_little_endian(unsigned int flags)
-{
-       return flags & TUN_VNET_LE || tun_legacy_is_little_endian(flags);
-}
-
-static inline u16 tun16_to_cpu(unsigned int flags, __virtio16 val)
-{
-       return __virtio16_to_cpu(tun_is_little_endian(flags), val);
-}
-
-static inline __virtio16 cpu_to_tun16(unsigned int flags, u16 val)
-{
-       return __cpu_to_virtio16(tun_is_little_endian(flags), val);
-}
-
-static long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
-                          unsigned int cmd, int __user *sp)
-{
-       int s;
-
-       switch (cmd) {
-       case TUNGETVNETHDRSZ:
-               s = *vnet_hdr_sz;
-               if (put_user(s, sp))
-                       return -EFAULT;
-               return 0;
-
-       case TUNSETVNETHDRSZ:
-               if (get_user(s, sp))
-                       return -EFAULT;
-               if (s < (int)sizeof(struct virtio_net_hdr))
-                       return -EINVAL;
-
-               *vnet_hdr_sz = s;
-               return 0;
-
-       case TUNGETVNETLE:
-               s = !!(*flags & TUN_VNET_LE);
-               if (put_user(s, sp))
-                       return -EFAULT;
-               return 0;
-
-       case TUNSETVNETLE:
-               if (get_user(s, sp))
-                       return -EFAULT;
-               if (s)
-                       *flags |= TUN_VNET_LE;
-               else
-                       *flags &= ~TUN_VNET_LE;
-               return 0;
-
-       case TUNGETVNETBE:
-               return tun_get_vnet_be(*flags, sp);
-
-       case TUNSETVNETBE:
-               return tun_set_vnet_be(flags, sp);
-
-       default:
-               return -EINVAL;
-       }
-}
-
-static int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from,
-                           struct virtio_net_hdr *hdr)
-{
-       u16 hdr_len;
-
-       if (iov_iter_count(from) < sz)
-               return -EINVAL;
-
-       if (!copy_from_iter_full(hdr, sizeof(*hdr), from))
-               return -EFAULT;
-
-       hdr_len = tun16_to_cpu(flags, hdr->hdr_len);
-
-       if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
-               hdr_len = max(tun16_to_cpu(flags, hdr->csum_start) + 
tun16_to_cpu(flags, hdr->csum_offset) + 2, hdr_len);
-               hdr->hdr_len = cpu_to_tun16(flags, hdr_len);
-       }
-
-       if (hdr_len > iov_iter_count(from))
-               return -EINVAL;
-
-       iov_iter_advance(from, sz - sizeof(*hdr));
-
-       return hdr_len;
-}
-
-static int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
-                           const struct virtio_net_hdr *hdr)
-{
-       if (unlikely(iov_iter_count(iter) < sz))
-               return -EINVAL;
-
-       if (unlikely(copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)))
-               return -EFAULT;
-
-       iov_iter_advance(iter, sz - sizeof(*hdr));
-
-       return 0;
-}
-
-static int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
-                              const struct virtio_net_hdr *hdr)
-{
-       return virtio_net_hdr_to_skb(skb, hdr, tun_is_little_endian(flags));
-}
-
-static int tun_vnet_hdr_from_skb(unsigned int flags,
-                                const struct net_device *dev,
-                                const struct sk_buff *skb,
-                                struct virtio_net_hdr *hdr)
-{
-       int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
-
-       if (virtio_net_hdr_from_skb(skb, hdr,
-                                   tun_is_little_endian(flags), true,
-                                   vlan_hlen)) {
-               struct skb_shared_info *sinfo = skb_shinfo(skb);
-
-               if (net_ratelimit()) {
-                       netdev_err(dev, "unexpected GSO type: 0x%x, gso_size 
%d, hdr_len %d\n",
-                                  sinfo->gso_type, tun16_to_cpu(flags, 
hdr->gso_size),
-                                  tun16_to_cpu(flags, hdr->hdr_len));
-                       print_hex_dump(KERN_ERR, "tun: ",
-                                      DUMP_PREFIX_NONE,
-                                      16, 1, skb->head,
-                                      min(tun16_to_cpu(flags, hdr->hdr_len), 
64), true);
-               }
-               WARN_ON_ONCE(1);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static inline u32 tun_hashfn(u32 rxhash)
 {
        return rxhash & TUN_MASK_FLOW_ENTRIES;
diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
new file mode 100644
index 
0000000000000000000000000000000000000000..dc5e9ec9d04cc8357504af23b1552af71155d329
--- /dev/null
+++ b/drivers/net/tun_vnet.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef TUN_VNET_H
+#define TUN_VNET_H
+
+/* High bits in flags field are unused. */
+#define TUN_VNET_LE     0x80000000
+#define TUN_VNET_BE     0x40000000
+
+static inline bool tun_vnet_legacy_is_little_endian(unsigned int flags)
+{
+       return !(IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
+                (flags & TUN_VNET_BE)) &&
+               virtio_legacy_is_little_endian();
+}
+
+static inline long tun_get_vnet_be(unsigned int flags, int __user *argp)
+{
+       int be = !!(flags & TUN_VNET_BE);
+
+       if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
+               return -EINVAL;
+
+       if (put_user(be, argp))
+               return -EFAULT;
+
+       return 0;
+}
+
+static inline long tun_set_vnet_be(unsigned int *flags, int __user *argp)
+{
+       int be;
+
+       if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
+               return -EINVAL;
+
+       if (get_user(be, argp))
+               return -EFAULT;
+
+       if (be)
+               *flags |= TUN_VNET_BE;
+       else
+               *flags &= ~TUN_VNET_BE;
+
+       return 0;
+}
+
+static inline bool tun_vnet_is_little_endian(unsigned int flags)
+{
+       return flags & TUN_VNET_LE || tun_vnet_legacy_is_little_endian(flags);
+}
+
+static inline u16 tun_vnet16_to_cpu(unsigned int flags, __virtio16 val)
+{
+       return __virtio16_to_cpu(tun_vnet_is_little_endian(flags), val);
+}
+
+static inline __virtio16 cpu_to_tun_vnet16(unsigned int flags, u16 val)
+{
+       return __cpu_to_virtio16(tun_vnet_is_little_endian(flags), val);
+}
+
+static inline long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
+                                 unsigned int cmd, int __user *sp)
+{
+       int s;
+
+       switch (cmd) {
+       case TUNGETVNETHDRSZ:
+               s = *vnet_hdr_sz;
+               if (put_user(s, sp))
+                       return -EFAULT;
+               return 0;
+
+       case TUNSETVNETHDRSZ:
+               if (get_user(s, sp))
+                       return -EFAULT;
+               if (s < (int)sizeof(struct virtio_net_hdr))
+                       return -EINVAL;
+
+               *vnet_hdr_sz = s;
+               return 0;
+
+       case TUNGETVNETLE:
+               s = !!(*flags & TUN_VNET_LE);
+               if (put_user(s, sp))
+                       return -EFAULT;
+               return 0;
+
+       case TUNSETVNETLE:
+               if (get_user(s, sp))
+                       return -EFAULT;
+               if (s)
+                       *flags |= TUN_VNET_LE;
+               else
+                       *flags &= ~TUN_VNET_LE;
+               return 0;
+
+       case TUNGETVNETBE:
+               return tun_get_vnet_be(*flags, sp);
+
+       case TUNSETVNETBE:
+               return tun_set_vnet_be(flags, sp);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static inline int tun_vnet_hdr_get(int sz, unsigned int flags,
+                                  struct iov_iter *from,
+                                  struct virtio_net_hdr *hdr)
+{
+       u16 hdr_len;
+
+       if (iov_iter_count(from) < sz)
+               return -EINVAL;
+
+       if (!copy_from_iter_full(hdr, sizeof(*hdr), from))
+               return -EFAULT;
+
+       hdr_len = tun_vnet16_to_cpu(flags, hdr->hdr_len);
+
+       if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+               hdr_len = max(tun_vnet16_to_cpu(flags, hdr->csum_start) + 
tun_vnet16_to_cpu(flags, hdr->csum_offset) + 2, hdr_len);
+               hdr->hdr_len = cpu_to_tun_vnet16(flags, hdr_len);
+       }
+
+       if (hdr_len > iov_iter_count(from))
+               return -EINVAL;
+
+       iov_iter_advance(from, sz - sizeof(*hdr));
+
+       return hdr_len;
+}
+
+static inline int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
+                                  const struct virtio_net_hdr *hdr)
+{
+       if (unlikely(iov_iter_count(iter) < sz))
+               return -EINVAL;
+
+       if (unlikely(copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)))
+               return -EFAULT;
+
+       iov_iter_advance(iter, sz - sizeof(*hdr));
+
+       return 0;
+}
+
+static inline int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
+                                     const struct virtio_net_hdr *hdr)
+{
+       return virtio_net_hdr_to_skb(skb, hdr, 
tun_vnet_is_little_endian(flags));
+}
+
+static inline int tun_vnet_hdr_from_skb(unsigned int flags,
+                                       const struct net_device *dev,
+                                       const struct sk_buff *skb,
+                                       struct virtio_net_hdr *hdr)
+{
+       int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
+
+       if (virtio_net_hdr_from_skb(skb, hdr,
+                                   tun_vnet_is_little_endian(flags), true,
+                                   vlan_hlen)) {
+               struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+               if (net_ratelimit()) {
+                       netdev_err(dev, "unexpected GSO type: 0x%x, gso_size 
%d, hdr_len %d\n",
+                                  sinfo->gso_type, tun_vnet16_to_cpu(flags, 
hdr->gso_size),
+                                  tun_vnet16_to_cpu(flags, hdr->hdr_len));
+                       print_hex_dump(KERN_ERR, "tun: ",
+                                      DUMP_PREFIX_NONE,
+                                      16, 1, skb->head,
+                                      min(tun_vnet16_to_cpu(flags, 
hdr->hdr_len), 64), true);
+               }
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#endif /* TUN_VNET_H */

-- 
2.48.1


Reply via email to