xref: /linux/drivers/net/tun_vnet.h (revision 1d41e2fa93f7d4dce4d05dfa2f980fba0898bea8)
1*1d41e2faSAkihiko Odaki /* SPDX-License-Identifier: GPL-2.0-or-later */
2*1d41e2faSAkihiko Odaki #ifndef TUN_VNET_H
3*1d41e2faSAkihiko Odaki #define TUN_VNET_H
4*1d41e2faSAkihiko Odaki 
5*1d41e2faSAkihiko Odaki /* High bits in flags field are unused. */
6*1d41e2faSAkihiko Odaki #define TUN_VNET_LE     0x80000000
7*1d41e2faSAkihiko Odaki #define TUN_VNET_BE     0x40000000
8*1d41e2faSAkihiko Odaki 
9*1d41e2faSAkihiko Odaki static inline bool tun_vnet_legacy_is_little_endian(unsigned int flags)
10*1d41e2faSAkihiko Odaki {
11*1d41e2faSAkihiko Odaki 	bool be = IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE) &&
12*1d41e2faSAkihiko Odaki 		  (flags & TUN_VNET_BE);
13*1d41e2faSAkihiko Odaki 
14*1d41e2faSAkihiko Odaki 	return !be && virtio_legacy_is_little_endian();
15*1d41e2faSAkihiko Odaki }
16*1d41e2faSAkihiko Odaki 
17*1d41e2faSAkihiko Odaki static inline long tun_get_vnet_be(unsigned int flags, int __user *argp)
18*1d41e2faSAkihiko Odaki {
19*1d41e2faSAkihiko Odaki 	int be = !!(flags & TUN_VNET_BE);
20*1d41e2faSAkihiko Odaki 
21*1d41e2faSAkihiko Odaki 	if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
22*1d41e2faSAkihiko Odaki 		return -EINVAL;
23*1d41e2faSAkihiko Odaki 
24*1d41e2faSAkihiko Odaki 	if (put_user(be, argp))
25*1d41e2faSAkihiko Odaki 		return -EFAULT;
26*1d41e2faSAkihiko Odaki 
27*1d41e2faSAkihiko Odaki 	return 0;
28*1d41e2faSAkihiko Odaki }
29*1d41e2faSAkihiko Odaki 
30*1d41e2faSAkihiko Odaki static inline long tun_set_vnet_be(unsigned int *flags, int __user *argp)
31*1d41e2faSAkihiko Odaki {
32*1d41e2faSAkihiko Odaki 	int be;
33*1d41e2faSAkihiko Odaki 
34*1d41e2faSAkihiko Odaki 	if (!IS_ENABLED(CONFIG_TUN_VNET_CROSS_LE))
35*1d41e2faSAkihiko Odaki 		return -EINVAL;
36*1d41e2faSAkihiko Odaki 
37*1d41e2faSAkihiko Odaki 	if (get_user(be, argp))
38*1d41e2faSAkihiko Odaki 		return -EFAULT;
39*1d41e2faSAkihiko Odaki 
40*1d41e2faSAkihiko Odaki 	if (be)
41*1d41e2faSAkihiko Odaki 		*flags |= TUN_VNET_BE;
42*1d41e2faSAkihiko Odaki 	else
43*1d41e2faSAkihiko Odaki 		*flags &= ~TUN_VNET_BE;
44*1d41e2faSAkihiko Odaki 
45*1d41e2faSAkihiko Odaki 	return 0;
46*1d41e2faSAkihiko Odaki }
47*1d41e2faSAkihiko Odaki 
48*1d41e2faSAkihiko Odaki static inline bool tun_vnet_is_little_endian(unsigned int flags)
49*1d41e2faSAkihiko Odaki {
50*1d41e2faSAkihiko Odaki 	return flags & TUN_VNET_LE || tun_vnet_legacy_is_little_endian(flags);
51*1d41e2faSAkihiko Odaki }
52*1d41e2faSAkihiko Odaki 
53*1d41e2faSAkihiko Odaki static inline u16 tun_vnet16_to_cpu(unsigned int flags, __virtio16 val)
54*1d41e2faSAkihiko Odaki {
55*1d41e2faSAkihiko Odaki 	return __virtio16_to_cpu(tun_vnet_is_little_endian(flags), val);
56*1d41e2faSAkihiko Odaki }
57*1d41e2faSAkihiko Odaki 
58*1d41e2faSAkihiko Odaki static inline __virtio16 cpu_to_tun_vnet16(unsigned int flags, u16 val)
59*1d41e2faSAkihiko Odaki {
60*1d41e2faSAkihiko Odaki 	return __cpu_to_virtio16(tun_vnet_is_little_endian(flags), val);
61*1d41e2faSAkihiko Odaki }
62*1d41e2faSAkihiko Odaki 
63*1d41e2faSAkihiko Odaki static inline long tun_vnet_ioctl(int *vnet_hdr_sz, unsigned int *flags,
64*1d41e2faSAkihiko Odaki 				  unsigned int cmd, int __user *sp)
65*1d41e2faSAkihiko Odaki {
66*1d41e2faSAkihiko Odaki 	int s;
67*1d41e2faSAkihiko Odaki 
68*1d41e2faSAkihiko Odaki 	switch (cmd) {
69*1d41e2faSAkihiko Odaki 	case TUNGETVNETHDRSZ:
70*1d41e2faSAkihiko Odaki 		s = *vnet_hdr_sz;
71*1d41e2faSAkihiko Odaki 		if (put_user(s, sp))
72*1d41e2faSAkihiko Odaki 			return -EFAULT;
73*1d41e2faSAkihiko Odaki 		return 0;
74*1d41e2faSAkihiko Odaki 
75*1d41e2faSAkihiko Odaki 	case TUNSETVNETHDRSZ:
76*1d41e2faSAkihiko Odaki 		if (get_user(s, sp))
77*1d41e2faSAkihiko Odaki 			return -EFAULT;
78*1d41e2faSAkihiko Odaki 		if (s < (int)sizeof(struct virtio_net_hdr))
79*1d41e2faSAkihiko Odaki 			return -EINVAL;
80*1d41e2faSAkihiko Odaki 
81*1d41e2faSAkihiko Odaki 		*vnet_hdr_sz = s;
82*1d41e2faSAkihiko Odaki 		return 0;
83*1d41e2faSAkihiko Odaki 
84*1d41e2faSAkihiko Odaki 	case TUNGETVNETLE:
85*1d41e2faSAkihiko Odaki 		s = !!(*flags & TUN_VNET_LE);
86*1d41e2faSAkihiko Odaki 		if (put_user(s, sp))
87*1d41e2faSAkihiko Odaki 			return -EFAULT;
88*1d41e2faSAkihiko Odaki 		return 0;
89*1d41e2faSAkihiko Odaki 
90*1d41e2faSAkihiko Odaki 	case TUNSETVNETLE:
91*1d41e2faSAkihiko Odaki 		if (get_user(s, sp))
92*1d41e2faSAkihiko Odaki 			return -EFAULT;
93*1d41e2faSAkihiko Odaki 		if (s)
94*1d41e2faSAkihiko Odaki 			*flags |= TUN_VNET_LE;
95*1d41e2faSAkihiko Odaki 		else
96*1d41e2faSAkihiko Odaki 			*flags &= ~TUN_VNET_LE;
97*1d41e2faSAkihiko Odaki 		return 0;
98*1d41e2faSAkihiko Odaki 
99*1d41e2faSAkihiko Odaki 	case TUNGETVNETBE:
100*1d41e2faSAkihiko Odaki 		return tun_get_vnet_be(*flags, sp);
101*1d41e2faSAkihiko Odaki 
102*1d41e2faSAkihiko Odaki 	case TUNSETVNETBE:
103*1d41e2faSAkihiko Odaki 		return tun_set_vnet_be(flags, sp);
104*1d41e2faSAkihiko Odaki 
105*1d41e2faSAkihiko Odaki 	default:
106*1d41e2faSAkihiko Odaki 		return -EINVAL;
107*1d41e2faSAkihiko Odaki 	}
108*1d41e2faSAkihiko Odaki }
109*1d41e2faSAkihiko Odaki 
110*1d41e2faSAkihiko Odaki static inline int tun_vnet_hdr_get(int sz, unsigned int flags,
111*1d41e2faSAkihiko Odaki 				   struct iov_iter *from,
112*1d41e2faSAkihiko Odaki 				   struct virtio_net_hdr *hdr)
113*1d41e2faSAkihiko Odaki {
114*1d41e2faSAkihiko Odaki 	u16 hdr_len;
115*1d41e2faSAkihiko Odaki 
116*1d41e2faSAkihiko Odaki 	if (iov_iter_count(from) < sz)
117*1d41e2faSAkihiko Odaki 		return -EINVAL;
118*1d41e2faSAkihiko Odaki 
119*1d41e2faSAkihiko Odaki 	if (!copy_from_iter_full(hdr, sizeof(*hdr), from))
120*1d41e2faSAkihiko Odaki 		return -EFAULT;
121*1d41e2faSAkihiko Odaki 
122*1d41e2faSAkihiko Odaki 	hdr_len = tun_vnet16_to_cpu(flags, hdr->hdr_len);
123*1d41e2faSAkihiko Odaki 
124*1d41e2faSAkihiko Odaki 	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
125*1d41e2faSAkihiko Odaki 		hdr_len = max(tun_vnet16_to_cpu(flags, hdr->csum_start) + tun_vnet16_to_cpu(flags, hdr->csum_offset) + 2, hdr_len);
126*1d41e2faSAkihiko Odaki 		hdr->hdr_len = cpu_to_tun_vnet16(flags, hdr_len);
127*1d41e2faSAkihiko Odaki 	}
128*1d41e2faSAkihiko Odaki 
129*1d41e2faSAkihiko Odaki 	if (hdr_len > iov_iter_count(from))
130*1d41e2faSAkihiko Odaki 		return -EINVAL;
131*1d41e2faSAkihiko Odaki 
132*1d41e2faSAkihiko Odaki 	iov_iter_advance(from, sz - sizeof(*hdr));
133*1d41e2faSAkihiko Odaki 
134*1d41e2faSAkihiko Odaki 	return hdr_len;
135*1d41e2faSAkihiko Odaki }
136*1d41e2faSAkihiko Odaki 
137*1d41e2faSAkihiko Odaki static inline int tun_vnet_hdr_put(int sz, struct iov_iter *iter,
138*1d41e2faSAkihiko Odaki 				   const struct virtio_net_hdr *hdr)
139*1d41e2faSAkihiko Odaki {
140*1d41e2faSAkihiko Odaki 	if (unlikely(iov_iter_count(iter) < sz))
141*1d41e2faSAkihiko Odaki 		return -EINVAL;
142*1d41e2faSAkihiko Odaki 
143*1d41e2faSAkihiko Odaki 	if (unlikely(copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)))
144*1d41e2faSAkihiko Odaki 		return -EFAULT;
145*1d41e2faSAkihiko Odaki 
146*1d41e2faSAkihiko Odaki 	iov_iter_advance(iter, sz - sizeof(*hdr));
147*1d41e2faSAkihiko Odaki 
148*1d41e2faSAkihiko Odaki 	return 0;
149*1d41e2faSAkihiko Odaki }
150*1d41e2faSAkihiko Odaki 
151*1d41e2faSAkihiko Odaki static inline int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb,
152*1d41e2faSAkihiko Odaki 				      const struct virtio_net_hdr *hdr)
153*1d41e2faSAkihiko Odaki {
154*1d41e2faSAkihiko Odaki 	return virtio_net_hdr_to_skb(skb, hdr, tun_vnet_is_little_endian(flags));
155*1d41e2faSAkihiko Odaki }
156*1d41e2faSAkihiko Odaki 
157*1d41e2faSAkihiko Odaki static inline int tun_vnet_hdr_from_skb(unsigned int flags,
158*1d41e2faSAkihiko Odaki 					const struct net_device *dev,
159*1d41e2faSAkihiko Odaki 					const struct sk_buff *skb,
160*1d41e2faSAkihiko Odaki 					struct virtio_net_hdr *hdr)
161*1d41e2faSAkihiko Odaki {
162*1d41e2faSAkihiko Odaki 	int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
163*1d41e2faSAkihiko Odaki 
164*1d41e2faSAkihiko Odaki 	if (virtio_net_hdr_from_skb(skb, hdr,
165*1d41e2faSAkihiko Odaki 				    tun_vnet_is_little_endian(flags), true,
166*1d41e2faSAkihiko Odaki 				    vlan_hlen)) {
167*1d41e2faSAkihiko Odaki 		struct skb_shared_info *sinfo = skb_shinfo(skb);
168*1d41e2faSAkihiko Odaki 
169*1d41e2faSAkihiko Odaki 		if (net_ratelimit()) {
170*1d41e2faSAkihiko Odaki 			netdev_err(dev, "unexpected GSO type: 0x%x, gso_size %d, hdr_len %d\n",
171*1d41e2faSAkihiko Odaki 				   sinfo->gso_type, tun_vnet16_to_cpu(flags, hdr->gso_size),
172*1d41e2faSAkihiko Odaki 				   tun_vnet16_to_cpu(flags, hdr->hdr_len));
173*1d41e2faSAkihiko Odaki 			print_hex_dump(KERN_ERR, "tun: ",
174*1d41e2faSAkihiko Odaki 				       DUMP_PREFIX_NONE,
175*1d41e2faSAkihiko Odaki 				       16, 1, skb->head,
176*1d41e2faSAkihiko Odaki 				       min(tun_vnet16_to_cpu(flags, hdr->hdr_len), 64), true);
177*1d41e2faSAkihiko Odaki 		}
178*1d41e2faSAkihiko Odaki 		WARN_ON_ONCE(1);
179*1d41e2faSAkihiko Odaki 		return -EINVAL;
180*1d41e2faSAkihiko Odaki 	}
181*1d41e2faSAkihiko Odaki 
182*1d41e2faSAkihiko Odaki 	return 0;
183*1d41e2faSAkihiko Odaki }
184*1d41e2faSAkihiko Odaki 
185*1d41e2faSAkihiko Odaki #endif /* TUN_VNET_H */
186