xref: /openbmc/linux/net/ipv6/sit.c (revision 1e952e95843d437b8a904dbd5b48d72db8ac23ec)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT)
41da177e4SLinus Torvalds  *	Linux INET6 implementation
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	Authors:
71da177e4SLinus Torvalds  *	Pedro Roque		<roque@di.fc.ul.pt>
81da177e4SLinus Torvalds  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *	Changes:
111da177e4SLinus Torvalds  * Roger Venning <r.venning@telstra.com>:	6to4 support
121da177e4SLinus Torvalds  * Nate Thompson <nate@thebog.net>:		6to4 support
13fadf6bf0STemplin, Fred L  * Fred Templin <fred.l.templin@boeing.com>:	isatap support
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
16f3213831SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17f3213831SJoe Perches 
181da177e4SLinus Torvalds #include <linux/module.h>
194fc268d2SRandy Dunlap #include <linux/capability.h>
201da177e4SLinus Torvalds #include <linux/errno.h>
211da177e4SLinus Torvalds #include <linux/types.h>
221da177e4SLinus Torvalds #include <linux/socket.h>
231da177e4SLinus Torvalds #include <linux/sockios.h>
241da177e4SLinus Torvalds #include <linux/net.h>
251da177e4SLinus Torvalds #include <linux/in6.h>
261da177e4SLinus Torvalds #include <linux/netdevice.h>
271da177e4SLinus Torvalds #include <linux/if_arp.h>
281da177e4SLinus Torvalds #include <linux/icmp.h>
295a0e3ad6STejun Heo #include <linux/slab.h>
307c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
311da177e4SLinus Torvalds #include <linux/init.h>
321da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
3346f25dffSKris Katterjohn #include <linux/if_ether.h>
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #include <net/sock.h>
361da177e4SLinus Torvalds #include <net/snmp.h>
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #include <net/ipv6.h>
391da177e4SLinus Torvalds #include <net/protocol.h>
401da177e4SLinus Torvalds #include <net/transp_v6.h>
411da177e4SLinus Torvalds #include <net/ip6_fib.h>
421da177e4SLinus Torvalds #include <net/ip6_route.h>
431da177e4SLinus Torvalds #include <net/ndisc.h>
441da177e4SLinus Torvalds #include <net/addrconf.h>
451da177e4SLinus Torvalds #include <net/ip.h>
461da177e4SLinus Torvalds #include <net/udp.h>
471da177e4SLinus Torvalds #include <net/icmp.h>
48c5441932SPravin B Shelar #include <net/ip_tunnels.h>
491da177e4SLinus Torvalds #include <net/inet_ecn.h>
501da177e4SLinus Torvalds #include <net/xfrm.h>
511da177e4SLinus Torvalds #include <net/dsfield.h>
528190d900SPavel Emelyanov #include <net/net_namespace.h>
538190d900SPavel Emelyanov #include <net/netns/generic.h>
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds /*
561da177e4SLinus Torvalds    This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds    For comments look at net/ipv4/ip_gre.c --ANK
591da177e4SLinus Torvalds  */
601da177e4SLinus Torvalds 
61e87a8f24SJiri Kosina #define IP6_SIT_HASH_SIZE  16
62e69a4adcSAl Viro #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
631da177e4SLinus Torvalds 
64f4e0b4c5SNicolas Dichtel static bool log_ecn_error = true;
65f4e0b4c5SNicolas Dichtel module_param(log_ecn_error, bool, 0644);
66f4e0b4c5SNicolas Dichtel MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
67f4e0b4c5SNicolas Dichtel 
6815fc1f70SEric Dumazet static int ipip6_tunnel_init(struct net_device *dev);
691da177e4SLinus Torvalds static void ipip6_tunnel_setup(struct net_device *dev);
7015fc1f70SEric Dumazet static void ipip6_dev_free(struct net_device *dev);
71218774dcSHannes Frederic Sowa static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst,
72218774dcSHannes Frederic Sowa 		      __be32 *v4dst);
73ba3e3f50SNicolas Dichtel static struct rtnl_link_ops sit_link_ops __read_mostly;
741da177e4SLinus Torvalds 
75c7d03a00SAlexey Dobriyan static unsigned int sit_net_id __read_mostly;
768190d900SPavel Emelyanov struct sit_net {
77e87a8f24SJiri Kosina 	struct ip_tunnel __rcu *tunnels_r_l[IP6_SIT_HASH_SIZE];
78e87a8f24SJiri Kosina 	struct ip_tunnel __rcu *tunnels_r[IP6_SIT_HASH_SIZE];
79e87a8f24SJiri Kosina 	struct ip_tunnel __rcu *tunnels_l[IP6_SIT_HASH_SIZE];
803a43be3cSEric Dumazet 	struct ip_tunnel __rcu *tunnels_wc[1];
813a43be3cSEric Dumazet 	struct ip_tunnel __rcu **tunnels[4];
8229182176SPavel Emelyanov 
83cd3dbc19SPavel Emelyanov 	struct net_device *fb_tunnel_dev;
848190d900SPavel Emelyanov };
858190d900SPavel Emelyanov 
dev_to_sit_net(struct net_device * dev)86fd5d687bSChristoph Hellwig static inline struct sit_net *dev_to_sit_net(struct net_device *dev)
87fd5d687bSChristoph Hellwig {
88fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
89fd5d687bSChristoph Hellwig 
90fd5d687bSChristoph Hellwig 	return net_generic(t->net, sit_net_id);
91fd5d687bSChristoph Hellwig }
92fd5d687bSChristoph Hellwig 
934543c10dSEric Dumazet /*
944543c10dSEric Dumazet  * Must be invoked with rcu_read_lock
954543c10dSEric Dumazet  */
ipip6_tunnel_lookup(struct net * net,struct net_device * dev,__be32 remote,__be32 local,int sifindex)96ca8def14SPavel Emelyanov static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net,
973051fbecSDavid Ahern 					     struct net_device *dev,
983051fbecSDavid Ahern 					     __be32 remote, __be32 local,
993051fbecSDavid Ahern 					     int sifindex)
1001da177e4SLinus Torvalds {
1013a43be3cSEric Dumazet 	unsigned int h0 = HASH(remote);
1023a43be3cSEric Dumazet 	unsigned int h1 = HASH(local);
1031da177e4SLinus Torvalds 	struct ip_tunnel *t;
10429182176SPavel Emelyanov 	struct sit_net *sitn = net_generic(net, sit_net_id);
1053051fbecSDavid Ahern 	int ifindex = dev ? dev->ifindex : 0;
1061da177e4SLinus Torvalds 
107e086cadcSAmerigo Wang 	for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) {
1081da177e4SLinus Torvalds 		if (local == t->parms.iph.saddr &&
1094fddbf5dSSascha Hlusiak 		    remote == t->parms.iph.daddr &&
1103051fbecSDavid Ahern 		    (!dev || !t->parms.link || ifindex == t->parms.link ||
1113051fbecSDavid Ahern 		     sifindex == t->parms.link) &&
1124fddbf5dSSascha Hlusiak 		    (t->dev->flags & IFF_UP))
1131da177e4SLinus Torvalds 			return t;
1141da177e4SLinus Torvalds 	}
115e086cadcSAmerigo Wang 	for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) {
1164fddbf5dSSascha Hlusiak 		if (remote == t->parms.iph.daddr &&
1173051fbecSDavid Ahern 		    (!dev || !t->parms.link || ifindex == t->parms.link ||
1183051fbecSDavid Ahern 		     sifindex == t->parms.link) &&
1194fddbf5dSSascha Hlusiak 		    (t->dev->flags & IFF_UP))
1201da177e4SLinus Torvalds 			return t;
1211da177e4SLinus Torvalds 	}
122e086cadcSAmerigo Wang 	for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) {
1234fddbf5dSSascha Hlusiak 		if (local == t->parms.iph.saddr &&
1243051fbecSDavid Ahern 		    (!dev || !t->parms.link || ifindex == t->parms.link ||
1253051fbecSDavid Ahern 		     sifindex == t->parms.link) &&
1264fddbf5dSSascha Hlusiak 		    (t->dev->flags & IFF_UP))
1271da177e4SLinus Torvalds 			return t;
1281da177e4SLinus Torvalds 	}
1294543c10dSEric Dumazet 	t = rcu_dereference(sitn->tunnels_wc[0]);
13053b24b8fSIan Morris 	if (t && (t->dev->flags & IFF_UP))
1311da177e4SLinus Torvalds 		return t;
1321da177e4SLinus Torvalds 	return NULL;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
__ipip6_bucket(struct sit_net * sitn,struct ip_tunnel_parm * parms)1353a43be3cSEric Dumazet static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn,
136ca8def14SPavel Emelyanov 		struct ip_tunnel_parm *parms)
1371da177e4SLinus Torvalds {
138420fe234SYOSHIFUJI Hideaki 	__be32 remote = parms->iph.daddr;
139420fe234SYOSHIFUJI Hideaki 	__be32 local = parms->iph.saddr;
1403a43be3cSEric Dumazet 	unsigned int h = 0;
1411da177e4SLinus Torvalds 	int prio = 0;
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	if (remote) {
1441da177e4SLinus Torvalds 		prio |= 2;
1451da177e4SLinus Torvalds 		h ^= HASH(remote);
1461da177e4SLinus Torvalds 	}
1471da177e4SLinus Torvalds 	if (local) {
1481da177e4SLinus Torvalds 		prio |= 1;
1491da177e4SLinus Torvalds 		h ^= HASH(local);
1501da177e4SLinus Torvalds 	}
15129182176SPavel Emelyanov 	return &sitn->tunnels[prio][h];
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds 
ipip6_bucket(struct sit_net * sitn,struct ip_tunnel * t)1543a43be3cSEric Dumazet static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn,
155ca8def14SPavel Emelyanov 		struct ip_tunnel *t)
156420fe234SYOSHIFUJI Hideaki {
157ca8def14SPavel Emelyanov 	return __ipip6_bucket(sitn, &t->parms);
158420fe234SYOSHIFUJI Hideaki }
159420fe234SYOSHIFUJI Hideaki 
ipip6_tunnel_unlink(struct sit_net * sitn,struct ip_tunnel * t)160ca8def14SPavel Emelyanov static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
1611da177e4SLinus Torvalds {
1623a43be3cSEric Dumazet 	struct ip_tunnel __rcu **tp;
1633a43be3cSEric Dumazet 	struct ip_tunnel *iter;
1641da177e4SLinus Torvalds 
1653a43be3cSEric Dumazet 	for (tp = ipip6_bucket(sitn, t);
1663a43be3cSEric Dumazet 	     (iter = rtnl_dereference(*tp)) != NULL;
1673a43be3cSEric Dumazet 	     tp = &iter->next) {
1683a43be3cSEric Dumazet 		if (t == iter) {
169cf778b00SEric Dumazet 			rcu_assign_pointer(*tp, t->next);
1701da177e4SLinus Torvalds 			break;
1711da177e4SLinus Torvalds 		}
1721da177e4SLinus Torvalds 	}
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds 
ipip6_tunnel_link(struct sit_net * sitn,struct ip_tunnel * t)175ca8def14SPavel Emelyanov static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
1761da177e4SLinus Torvalds {
1773a43be3cSEric Dumazet 	struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
1781da177e4SLinus Torvalds 
179cf778b00SEric Dumazet 	rcu_assign_pointer(t->next, rtnl_dereference(*tp));
180cf778b00SEric Dumazet 	rcu_assign_pointer(*tp, t);
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
ipip6_tunnel_clone_6rd(struct net_device * dev,struct sit_net * sitn)183e0c93948SYOSHIFUJI Hideaki / 吉藤英明 static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
184fa857afcSYOSHIFUJI Hideaki / 吉藤英明 {
185fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #ifdef CONFIG_IPV6_SIT_6RD
186e0c93948SYOSHIFUJI Hideaki / 吉藤英明 	struct ip_tunnel *t = netdev_priv(dev);
187e0c93948SYOSHIFUJI Hideaki / 吉藤英明 
18879134e6cSEric Dumazet 	if (dev == sitn->fb_tunnel_dev || !sitn->fb_tunnel_dev) {
189fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
190fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		t->ip6rd.relay_prefix = 0;
191fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		t->ip6rd.prefixlen = 16;
192fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		t->ip6rd.relay_prefixlen = 0;
193fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	} else {
194fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
195fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
196fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	}
197fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #endif
198fa857afcSYOSHIFUJI Hideaki / 吉藤英明 }
199fa857afcSYOSHIFUJI Hideaki / 吉藤英明 
ipip6_tunnel_create(struct net_device * dev)200f3723416SNicolas Dichtel static int ipip6_tunnel_create(struct net_device *dev)
201f3723416SNicolas Dichtel {
202f3723416SNicolas Dichtel 	struct ip_tunnel *t = netdev_priv(dev);
203f3723416SNicolas Dichtel 	struct net *net = dev_net(dev);
204f3723416SNicolas Dichtel 	struct sit_net *sitn = net_generic(net, sit_net_id);
205f3723416SNicolas Dichtel 	int err;
206f3723416SNicolas Dichtel 
2075a1b7e1aSJakub Kicinski 	__dev_addr_set(dev, &t->parms.iph.saddr, 4);
208ebe084aaSSteffen Klassert 	memcpy(dev->broadcast, &t->parms.iph.daddr, 4);
209f3723416SNicolas Dichtel 
210d440b720SNicolas Dichtel 	if ((__force u16)t->parms.i_flags & SIT_ISATAP)
211f3723416SNicolas Dichtel 		dev->priv_flags |= IFF_ISATAP;
212f3723416SNicolas Dichtel 
21387e57399SThadeu Lima de Souza Cascardo 	dev->rtnl_link_ops = &sit_link_ops;
21487e57399SThadeu Lima de Souza Cascardo 
215f3723416SNicolas Dichtel 	err = register_netdevice(dev);
216f3723416SNicolas Dichtel 	if (err < 0)
217f3723416SNicolas Dichtel 		goto out;
218f3723416SNicolas Dichtel 
219ebe084aaSSteffen Klassert 	ipip6_tunnel_clone_6rd(dev, sitn);
220ebe084aaSSteffen Klassert 
221f3723416SNicolas Dichtel 	ipip6_tunnel_link(sitn, t);
222f3723416SNicolas Dichtel 	return 0;
223f3723416SNicolas Dichtel 
224f3723416SNicolas Dichtel out:
225f3723416SNicolas Dichtel 	return err;
226f3723416SNicolas Dichtel }
227f3723416SNicolas Dichtel 
ipip6_tunnel_locate(struct net * net,struct ip_tunnel_parm * parms,int create)228ca8def14SPavel Emelyanov static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
229ca8def14SPavel Emelyanov 		struct ip_tunnel_parm *parms, int create)
2301da177e4SLinus Torvalds {
231e69a4adcSAl Viro 	__be32 remote = parms->iph.daddr;
232e69a4adcSAl Viro 	__be32 local = parms->iph.saddr;
2333a43be3cSEric Dumazet 	struct ip_tunnel *t, *nt;
2343a43be3cSEric Dumazet 	struct ip_tunnel __rcu **tp;
2351da177e4SLinus Torvalds 	struct net_device *dev;
2361da177e4SLinus Torvalds 	char name[IFNAMSIZ];
237ca8def14SPavel Emelyanov 	struct sit_net *sitn = net_generic(net, sit_net_id);
2381da177e4SLinus Torvalds 
2393a43be3cSEric Dumazet 	for (tp = __ipip6_bucket(sitn, parms);
2403a43be3cSEric Dumazet 	    (t = rtnl_dereference(*tp)) != NULL;
2413a43be3cSEric Dumazet 	     tp = &t->next) {
2428db99e57SSascha Hlusiak 		if (local == t->parms.iph.saddr &&
2434fddbf5dSSascha Hlusiak 		    remote == t->parms.iph.daddr &&
2444fddbf5dSSascha Hlusiak 		    parms->link == t->parms.link) {
2458db99e57SSascha Hlusiak 			if (create)
2468db99e57SSascha Hlusiak 				return NULL;
2478db99e57SSascha Hlusiak 			else
2481da177e4SLinus Torvalds 				return t;
2491da177e4SLinus Torvalds 		}
2508db99e57SSascha Hlusiak 	}
2511da177e4SLinus Torvalds 	if (!create)
2521da177e4SLinus Torvalds 		goto failed;
2531da177e4SLinus Torvalds 
254b95211e0SEric Dumazet 	if (parms->name[0]) {
255b95211e0SEric Dumazet 		if (!dev_valid_name(parms->name))
256b95211e0SEric Dumazet 			goto failed;
2577574cc58SWolfram Sang 		strscpy(name, parms->name, IFNAMSIZ);
258b95211e0SEric Dumazet 	} else {
25915fc1f70SEric Dumazet 		strcpy(name, "sit%d");
260b95211e0SEric Dumazet 	}
261c835a677STom Gundersen 	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
262c835a677STom Gundersen 			   ipip6_tunnel_setup);
26363159f29SIan Morris 	if (!dev)
2641da177e4SLinus Torvalds 		return NULL;
2651da177e4SLinus Torvalds 
2667a97146cSPavel Emelyanov 	dev_net_set(dev, net);
2677a97146cSPavel Emelyanov 
2682941a486SPatrick McHardy 	nt = netdev_priv(dev);
2691326c3d5SStephen Hemminger 
2701da177e4SLinus Torvalds 	nt->parms = *parms;
271f3723416SNicolas Dichtel 	if (ipip6_tunnel_create(dev) < 0)
272b37d428bSPavel Emelyanov 		goto failed_free;
2731da177e4SLinus Torvalds 
274261ba78cSzhang kai 	if (!parms->name[0])
275261ba78cSzhang kai 		strcpy(parms->name, dev->name);
276261ba78cSzhang kai 
2771da177e4SLinus Torvalds 	return nt;
2781da177e4SLinus Torvalds 
279b37d428bSPavel Emelyanov failed_free:
280cf124db5SDavid S. Miller 	free_netdev(dev);
2811da177e4SLinus Torvalds failed:
2821da177e4SLinus Torvalds 	return NULL;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds 
285ef9a9d11SEric Dumazet #define for_each_prl_rcu(start)			\
286ef9a9d11SEric Dumazet 	for (prl = rcu_dereference(start);	\
287ef9a9d11SEric Dumazet 	     prl;				\
288ef9a9d11SEric Dumazet 	     prl = rcu_dereference(prl->next))
289ef9a9d11SEric Dumazet 
290fadf6bf0STemplin, Fred L static struct ip_tunnel_prl_entry *
__ipip6_tunnel_locate_prl(struct ip_tunnel * t,__be32 addr)2913fcfa129SYOSHIFUJI Hideaki __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
292fadf6bf0STemplin, Fred L {
293ef9a9d11SEric Dumazet 	struct ip_tunnel_prl_entry *prl;
294fadf6bf0STemplin, Fred L 
295ef9a9d11SEric Dumazet 	for_each_prl_rcu(t->prl)
296ef9a9d11SEric Dumazet 		if (prl->addr == addr)
297fadf6bf0STemplin, Fred L 			break;
298ef9a9d11SEric Dumazet 	return prl;
299fadf6bf0STemplin, Fred L 
300fadf6bf0STemplin, Fred L }
301fadf6bf0STemplin, Fred L 
ipip6_tunnel_get_prl(struct net_device * dev,struct ip_tunnel_prl __user * a)3023e7a1c7cSArnd Bergmann static int ipip6_tunnel_get_prl(struct net_device *dev, struct ip_tunnel_prl __user *a)
303300aaeeaSYOSHIFUJI Hideaki {
304fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
3052b4743bdSYOSHIFUJI Hideaki 	struct ip_tunnel_prl kprl, *kp;
306300aaeeaSYOSHIFUJI Hideaki 	struct ip_tunnel_prl_entry *prl;
307300aaeeaSYOSHIFUJI Hideaki 	unsigned int cmax, c = 0, ca, len;
308300aaeeaSYOSHIFUJI Hideaki 	int ret = 0;
309300aaeeaSYOSHIFUJI Hideaki 
310fd5d687bSChristoph Hellwig 	if (dev == dev_to_sit_net(dev)->fb_tunnel_dev)
311fd5d687bSChristoph Hellwig 		return -EINVAL;
312fd5d687bSChristoph Hellwig 
3132b4743bdSYOSHIFUJI Hideaki 	if (copy_from_user(&kprl, a, sizeof(kprl)))
3142b4743bdSYOSHIFUJI Hideaki 		return -EFAULT;
3152b4743bdSYOSHIFUJI Hideaki 	cmax = kprl.datalen / sizeof(kprl);
3162b4743bdSYOSHIFUJI Hideaki 	if (cmax > 1 && kprl.addr != htonl(INADDR_ANY))
317300aaeeaSYOSHIFUJI Hideaki 		cmax = 1;
318300aaeeaSYOSHIFUJI Hideaki 
319300aaeeaSYOSHIFUJI Hideaki 	/* For simple GET or for root users,
320300aaeeaSYOSHIFUJI Hideaki 	 * we try harder to allocate.
321300aaeeaSYOSHIFUJI Hideaki 	 */
322300aaeeaSYOSHIFUJI Hideaki 	kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ?
3231b51d827SVasily Averin 		kcalloc(cmax, sizeof(*kp), GFP_KERNEL_ACCOUNT | __GFP_NOWARN) :
324300aaeeaSYOSHIFUJI Hideaki 		NULL;
325300aaeeaSYOSHIFUJI Hideaki 
326284fda1eSkernel test robot 	ca = min(t->prl_count, cmax);
327300aaeeaSYOSHIFUJI Hideaki 
328300aaeeaSYOSHIFUJI Hideaki 	if (!kp) {
329300aaeeaSYOSHIFUJI Hideaki 		/* We don't try hard to allocate much memory for
330300aaeeaSYOSHIFUJI Hideaki 		 * non-root users.
331300aaeeaSYOSHIFUJI Hideaki 		 * For root users, retry allocating enough memory for
332300aaeeaSYOSHIFUJI Hideaki 		 * the answer.
333300aaeeaSYOSHIFUJI Hideaki 		 */
3341b51d827SVasily Averin 		kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC | __GFP_ACCOUNT |
3351b51d827SVasily Averin 					      __GFP_NOWARN);
336300aaeeaSYOSHIFUJI Hideaki 		if (!kp) {
337300aaeeaSYOSHIFUJI Hideaki 			ret = -ENOMEM;
338300aaeeaSYOSHIFUJI Hideaki 			goto out;
339300aaeeaSYOSHIFUJI Hideaki 		}
340300aaeeaSYOSHIFUJI Hideaki 	}
341300aaeeaSYOSHIFUJI Hideaki 
342adabdd8fSkatrinzhou 	rcu_read_lock();
343ef9a9d11SEric Dumazet 	for_each_prl_rcu(t->prl) {
344298bf12dSSascha Hlusiak 		if (c >= cmax)
345300aaeeaSYOSHIFUJI Hideaki 			break;
3462b4743bdSYOSHIFUJI Hideaki 		if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
347300aaeeaSYOSHIFUJI Hideaki 			continue;
348300aaeeaSYOSHIFUJI Hideaki 		kp[c].addr = prl->addr;
349300aaeeaSYOSHIFUJI Hideaki 		kp[c].flags = prl->flags;
350300aaeeaSYOSHIFUJI Hideaki 		c++;
3512b4743bdSYOSHIFUJI Hideaki 		if (kprl.addr != htonl(INADDR_ANY))
352300aaeeaSYOSHIFUJI Hideaki 			break;
353300aaeeaSYOSHIFUJI Hideaki 	}
354adabdd8fSkatrinzhou 
355ef9a9d11SEric Dumazet 	rcu_read_unlock();
356300aaeeaSYOSHIFUJI Hideaki 
357300aaeeaSYOSHIFUJI Hideaki 	len = sizeof(*kp) * c;
3582b4743bdSYOSHIFUJI Hideaki 	ret = 0;
3592b4743bdSYOSHIFUJI Hideaki 	if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
3602b4743bdSYOSHIFUJI Hideaki 		ret = -EFAULT;
361300aaeeaSYOSHIFUJI Hideaki 
362300aaeeaSYOSHIFUJI Hideaki 	kfree(kp);
363adabdd8fSkatrinzhou out:
3642b4743bdSYOSHIFUJI Hideaki 	return ret;
365300aaeeaSYOSHIFUJI Hideaki }
366300aaeeaSYOSHIFUJI Hideaki 
367fadf6bf0STemplin, Fred L static int
ipip6_tunnel_add_prl(struct ip_tunnel * t,struct ip_tunnel_prl * a,int chg)368fadf6bf0STemplin, Fred L ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
369fadf6bf0STemplin, Fred L {
370fadf6bf0STemplin, Fred L 	struct ip_tunnel_prl_entry *p;
3713fcfa129SYOSHIFUJI Hideaki 	int err = 0;
3723fcfa129SYOSHIFUJI Hideaki 
3730009ae1fSYOSHIFUJI Hideaki 	if (a->addr == htonl(INADDR_ANY))
3740009ae1fSYOSHIFUJI Hideaki 		return -EINVAL;
3750009ae1fSYOSHIFUJI Hideaki 
376aac4dddcSEric Dumazet 	ASSERT_RTNL();
377fadf6bf0STemplin, Fred L 
3783a43be3cSEric Dumazet 	for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) {
379300aaeeaSYOSHIFUJI Hideaki 		if (p->addr == a->addr) {
380ef9a9d11SEric Dumazet 			if (chg) {
381ef9a9d11SEric Dumazet 				p->flags = a->flags;
382ef9a9d11SEric Dumazet 				goto out;
383ef9a9d11SEric Dumazet 			}
3843fcfa129SYOSHIFUJI Hideaki 			err = -EEXIST;
3853fcfa129SYOSHIFUJI Hideaki 			goto out;
386fadf6bf0STemplin, Fred L 		}
387fadf6bf0STemplin, Fred L 	}
388fadf6bf0STemplin, Fred L 
3893fcfa129SYOSHIFUJI Hideaki 	if (chg) {
3903fcfa129SYOSHIFUJI Hideaki 		err = -ENXIO;
3913fcfa129SYOSHIFUJI Hideaki 		goto out;
3923fcfa129SYOSHIFUJI Hideaki 	}
393fadf6bf0STemplin, Fred L 
394fadf6bf0STemplin, Fred L 	p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL);
3953fcfa129SYOSHIFUJI Hideaki 	if (!p) {
3963fcfa129SYOSHIFUJI Hideaki 		err = -ENOBUFS;
3973fcfa129SYOSHIFUJI Hideaki 		goto out;
3983fcfa129SYOSHIFUJI Hideaki 	}
399fadf6bf0STemplin, Fred L 
400fadf6bf0STemplin, Fred L 	p->next = t->prl;
401300aaeeaSYOSHIFUJI Hideaki 	p->addr = a->addr;
402300aaeeaSYOSHIFUJI Hideaki 	p->flags = a->flags;
403ef9a9d11SEric Dumazet 	t->prl_count++;
404cf778b00SEric Dumazet 	rcu_assign_pointer(t->prl, p);
4053fcfa129SYOSHIFUJI Hideaki out:
4063fcfa129SYOSHIFUJI Hideaki 	return err;
407fadf6bf0STemplin, Fred L }
408fadf6bf0STemplin, Fred L 
prl_list_destroy_rcu(struct rcu_head * head)409ef9a9d11SEric Dumazet static void prl_list_destroy_rcu(struct rcu_head *head)
410ef9a9d11SEric Dumazet {
411ef9a9d11SEric Dumazet 	struct ip_tunnel_prl_entry *p, *n;
412ef9a9d11SEric Dumazet 
413ef9a9d11SEric Dumazet 	p = container_of(head, struct ip_tunnel_prl_entry, rcu_head);
414ef9a9d11SEric Dumazet 	do {
415753ea8e9SEric Dumazet 		n = rcu_dereference_protected(p->next, 1);
416ef9a9d11SEric Dumazet 		kfree(p);
417ef9a9d11SEric Dumazet 		p = n;
418ef9a9d11SEric Dumazet 	} while (p);
419ef9a9d11SEric Dumazet }
420ef9a9d11SEric Dumazet 
421fadf6bf0STemplin, Fred L static int
ipip6_tunnel_del_prl(struct ip_tunnel * t,struct ip_tunnel_prl * a)422fadf6bf0STemplin, Fred L ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
423fadf6bf0STemplin, Fred L {
424753ea8e9SEric Dumazet 	struct ip_tunnel_prl_entry *x;
425753ea8e9SEric Dumazet 	struct ip_tunnel_prl_entry __rcu **p;
4263fcfa129SYOSHIFUJI Hideaki 	int err = 0;
4273fcfa129SYOSHIFUJI Hideaki 
428aac4dddcSEric Dumazet 	ASSERT_RTNL();
429fadf6bf0STemplin, Fred L 
4300009ae1fSYOSHIFUJI Hideaki 	if (a && a->addr != htonl(INADDR_ANY)) {
431753ea8e9SEric Dumazet 		for (p = &t->prl;
432753ea8e9SEric Dumazet 		     (x = rtnl_dereference(*p)) != NULL;
433753ea8e9SEric Dumazet 		     p = &x->next) {
434753ea8e9SEric Dumazet 			if (x->addr == a->addr) {
435fadf6bf0STemplin, Fred L 				*p = x->next;
43611c476f3SPaul E. McKenney 				kfree_rcu(x, rcu_head);
437300aaeeaSYOSHIFUJI Hideaki 				t->prl_count--;
4383fcfa129SYOSHIFUJI Hideaki 				goto out;
439fadf6bf0STemplin, Fred L 			}
440fadf6bf0STemplin, Fred L 		}
4413fcfa129SYOSHIFUJI Hideaki 		err = -ENXIO;
442fadf6bf0STemplin, Fred L 	} else {
443753ea8e9SEric Dumazet 		x = rtnl_dereference(t->prl);
444753ea8e9SEric Dumazet 		if (x) {
445ef9a9d11SEric Dumazet 			t->prl_count = 0;
446ef9a9d11SEric Dumazet 			call_rcu(&x->rcu_head, prl_list_destroy_rcu);
447ef9a9d11SEric Dumazet 			t->prl = NULL;
448fadf6bf0STemplin, Fred L 		}
449fadf6bf0STemplin, Fred L 	}
4503fcfa129SYOSHIFUJI Hideaki out:
4514b279601SSascha Hlusiak 	return err;
452fadf6bf0STemplin, Fred L }
453fadf6bf0STemplin, Fred L 
ipip6_tunnel_prl_ctl(struct net_device * dev,struct ip_tunnel_prl __user * data,int cmd)4543e7a1c7cSArnd Bergmann static int ipip6_tunnel_prl_ctl(struct net_device *dev,
4553e7a1c7cSArnd Bergmann 				struct ip_tunnel_prl __user *data, int cmd)
456fd5d687bSChristoph Hellwig {
457fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
458fd5d687bSChristoph Hellwig 	struct ip_tunnel_prl prl;
459fd5d687bSChristoph Hellwig 	int err;
460fd5d687bSChristoph Hellwig 
461fd5d687bSChristoph Hellwig 	if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
462fd5d687bSChristoph Hellwig 		return -EPERM;
463fd5d687bSChristoph Hellwig 	if (dev == dev_to_sit_net(dev)->fb_tunnel_dev)
464fd5d687bSChristoph Hellwig 		return -EINVAL;
465fd5d687bSChristoph Hellwig 
4663e7a1c7cSArnd Bergmann 	if (copy_from_user(&prl, data, sizeof(prl)))
467fd5d687bSChristoph Hellwig 		return -EFAULT;
468fd5d687bSChristoph Hellwig 
469fd5d687bSChristoph Hellwig 	switch (cmd) {
470fd5d687bSChristoph Hellwig 	case SIOCDELPRL:
471fd5d687bSChristoph Hellwig 		err = ipip6_tunnel_del_prl(t, &prl);
472fd5d687bSChristoph Hellwig 		break;
473fd5d687bSChristoph Hellwig 	case SIOCADDPRL:
474fd5d687bSChristoph Hellwig 	case SIOCCHGPRL:
475fd5d687bSChristoph Hellwig 		err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
476fd5d687bSChristoph Hellwig 		break;
477fd5d687bSChristoph Hellwig 	}
478fd5d687bSChristoph Hellwig 	dst_cache_reset(&t->dst_cache);
479fd5d687bSChristoph Hellwig 	netdev_state_change(dev);
480fd5d687bSChristoph Hellwig 	return err;
481fd5d687bSChristoph Hellwig }
482fd5d687bSChristoph Hellwig 
483fadf6bf0STemplin, Fred L static int
isatap_chksrc(struct sk_buff * skb,const struct iphdr * iph,struct ip_tunnel * t)484b71d1d42SEric Dumazet isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
485fadf6bf0STemplin, Fred L {
4863fcfa129SYOSHIFUJI Hideaki 	struct ip_tunnel_prl_entry *p;
487fadf6bf0STemplin, Fred L 	int ok = 1;
488fadf6bf0STemplin, Fred L 
489ef9a9d11SEric Dumazet 	rcu_read_lock();
4903fcfa129SYOSHIFUJI Hideaki 	p = __ipip6_tunnel_locate_prl(t, iph->saddr);
491fadf6bf0STemplin, Fred L 	if (p) {
492300aaeeaSYOSHIFUJI Hideaki 		if (p->flags & PRL_DEFAULT)
493fadf6bf0STemplin, Fred L 			skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT;
494fadf6bf0STemplin, Fred L 		else
495fadf6bf0STemplin, Fred L 			skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
496fadf6bf0STemplin, Fred L 	} else {
497b71d1d42SEric Dumazet 		const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
498b71d1d42SEric Dumazet 
499fadf6bf0STemplin, Fred L 		if (ipv6_addr_is_isatap(addr6) &&
500fadf6bf0STemplin, Fred L 		    (addr6->s6_addr32[3] == iph->saddr) &&
50152eeeb84SYOSHIFUJI Hideaki 		    ipv6_chk_prefix(addr6, t->dev))
502fadf6bf0STemplin, Fred L 			skb->ndisc_nodetype = NDISC_NODETYPE_HOST;
503fadf6bf0STemplin, Fred L 		else
504fadf6bf0STemplin, Fred L 			ok = 0;
505fadf6bf0STemplin, Fred L 	}
506ef9a9d11SEric Dumazet 	rcu_read_unlock();
507fadf6bf0STemplin, Fred L 	return ok;
508fadf6bf0STemplin, Fred L }
509fadf6bf0STemplin, Fred L 
ipip6_tunnel_uninit(struct net_device * dev)5101da177e4SLinus Torvalds static void ipip6_tunnel_uninit(struct net_device *dev)
5111da177e4SLinus Torvalds {
5125e6700b3SNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
5135e6700b3SNicolas Dichtel 	struct sit_net *sitn = net_generic(tunnel->net, sit_net_id);
514ca8def14SPavel Emelyanov 
515cd3dbc19SPavel Emelyanov 	if (dev == sitn->fb_tunnel_dev) {
516a9b3cd7fSStephen Hemminger 		RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL);
5171da177e4SLinus Torvalds 	} else {
5185e6700b3SNicolas Dichtel 		ipip6_tunnel_unlink(sitn, tunnel);
5195e6700b3SNicolas Dichtel 		ipip6_tunnel_del_prl(tunnel, NULL);
5201da177e4SLinus Torvalds 	}
521e09acddfSPaolo Abeni 	dst_cache_reset(&tunnel->dst_cache);
522d62607c3SJakub Kicinski 	netdev_put(dev, &tunnel->dev_tracker);
5231da177e4SLinus Torvalds }
5241da177e4SLinus Torvalds 
ipip6_err(struct sk_buff * skb,u32 info)525c73cb5a2SKazunori MIYAZAWA static int ipip6_err(struct sk_buff *skb, u32 info)
5261da177e4SLinus Torvalds {
527b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
52888c7664fSArnaldo Carvalho de Melo 	const int type = icmp_hdr(skb)->type;
52988c7664fSArnaldo Carvalho de Melo 	const int code = icmp_hdr(skb)->code;
53020e1954fSEric Dumazet 	unsigned int data_len = 0;
5311da177e4SLinus Torvalds 	struct ip_tunnel *t;
5323051fbecSDavid Ahern 	int sifindex;
533c73cb5a2SKazunori MIYAZAWA 	int err;
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	switch (type) {
5361da177e4SLinus Torvalds 	default:
5371da177e4SLinus Torvalds 	case ICMP_PARAMETERPROB:
538c73cb5a2SKazunori MIYAZAWA 		return 0;
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 	case ICMP_DEST_UNREACH:
5411da177e4SLinus Torvalds 		switch (code) {
5421da177e4SLinus Torvalds 		case ICMP_SR_FAILED:
5431da177e4SLinus Torvalds 			/* Impossible event. */
544c73cb5a2SKazunori MIYAZAWA 			return 0;
5451da177e4SLinus Torvalds 		default:
5461da177e4SLinus Torvalds 			/* All others are translated to HOST_UNREACH.
5471da177e4SLinus Torvalds 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
5481da177e4SLinus Torvalds 			   I believe they are just ether pollution. --ANK
5491da177e4SLinus Torvalds 			 */
5501da177e4SLinus Torvalds 			break;
5511da177e4SLinus Torvalds 		}
5521da177e4SLinus Torvalds 		break;
5531da177e4SLinus Torvalds 	case ICMP_TIME_EXCEEDED:
5541da177e4SLinus Torvalds 		if (code != ICMP_EXC_TTL)
555c73cb5a2SKazunori MIYAZAWA 			return 0;
55620e1954fSEric Dumazet 		data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
5571da177e4SLinus Torvalds 		break;
558ec18d9a2SDavid S. Miller 	case ICMP_REDIRECT:
559ec18d9a2SDavid S. Miller 		break;
5601da177e4SLinus Torvalds 	}
5611da177e4SLinus Torvalds 
562c73cb5a2SKazunori MIYAZAWA 	err = -ENOENT;
563c73cb5a2SKazunori MIYAZAWA 
5643051fbecSDavid Ahern 	sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0;
5653051fbecSDavid Ahern 	t = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
5663051fbecSDavid Ahern 				iph->daddr, iph->saddr, sifindex);
56763159f29SIan Morris 	if (!t)
56836393395SDavid S. Miller 		goto out;
56936393395SDavid S. Miller 
57036393395SDavid S. Miller 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
57136393395SDavid S. Miller 		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
572d888f396SMaciej Żenczykowski 				 t->parms.link, iph->protocol);
57336393395SDavid S. Miller 		err = 0;
57436393395SDavid S. Miller 		goto out;
57536393395SDavid S. Miller 	}
576ec18d9a2SDavid S. Miller 	if (type == ICMP_REDIRECT) {
5771042caa7SMaciej Żenczykowski 		ipv4_redirect(skb, dev_net(skb->dev), t->parms.link,
5781042caa7SMaciej Żenczykowski 			      iph->protocol);
579ec18d9a2SDavid S. Miller 		err = 0;
580ec18d9a2SDavid S. Miller 		goto out;
581ec18d9a2SDavid S. Miller 	}
58236393395SDavid S. Miller 
5832d7a3b27SEric Dumazet 	err = 0;
584173656acSHangbin Liu 	if (__in6_dev_get(skb->dev) &&
585173656acSHangbin Liu 	    !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len))
5861da177e4SLinus Torvalds 		goto out;
587c73cb5a2SKazunori MIYAZAWA 
5882d7a3b27SEric Dumazet 	if (t->parms.iph.daddr == 0)
589ca15a078SOussama Ghorbel 		goto out;
590ca15a078SOussama Ghorbel 
5911da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
5921da177e4SLinus Torvalds 		goto out;
5931da177e4SLinus Torvalds 
594bb80087aSWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
5951da177e4SLinus Torvalds 		t->err_count++;
5961da177e4SLinus Torvalds 	else
5971da177e4SLinus Torvalds 		t->err_count = 1;
5981da177e4SLinus Torvalds 	t->err_time = jiffies;
5991da177e4SLinus Torvalds out:
600c73cb5a2SKazunori MIYAZAWA 	return err;
6011da177e4SLinus Torvalds }
6021da177e4SLinus Torvalds 
is_spoofed_6rd(struct ip_tunnel * tunnel,const __be32 v4addr,const struct in6_addr * v6addr)603218774dcSHannes Frederic Sowa static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr,
604218774dcSHannes Frederic Sowa 				  const struct in6_addr *v6addr)
605218774dcSHannes Frederic Sowa {
606218774dcSHannes Frederic Sowa 	__be32 v4embed = 0;
607218774dcSHannes Frederic Sowa 	if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed)
608218774dcSHannes Frederic Sowa 		return true;
609218774dcSHannes Frederic Sowa 	return false;
610218774dcSHannes Frederic Sowa }
611218774dcSHannes Frederic Sowa 
6127df37ff3SCatalin\(ux\) M. BOIE /* Checks if an address matches an address on the tunnel interface.
6137df37ff3SCatalin\(ux\) M. BOIE  * Used to detect the NAT of proto 41 packets and let them pass spoofing test.
6147df37ff3SCatalin\(ux\) M. BOIE  * Long story:
6157df37ff3SCatalin\(ux\) M. BOIE  * This function is called after we considered the packet as spoofed
6167df37ff3SCatalin\(ux\) M. BOIE  * in is_spoofed_6rd.
6177df37ff3SCatalin\(ux\) M. BOIE  * We may have a router that is doing NAT for proto 41 packets
6187df37ff3SCatalin\(ux\) M. BOIE  * for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb
6197df37ff3SCatalin\(ux\) M. BOIE  * will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd
6207df37ff3SCatalin\(ux\) M. BOIE  * function will return true, dropping the packet.
6217df37ff3SCatalin\(ux\) M. BOIE  * But, we can still check if is spoofed against the IP
6227df37ff3SCatalin\(ux\) M. BOIE  * addresses associated with the interface.
6237df37ff3SCatalin\(ux\) M. BOIE  */
only_dnatted(const struct ip_tunnel * tunnel,const struct in6_addr * v6dst)6247df37ff3SCatalin\(ux\) M. BOIE static bool only_dnatted(const struct ip_tunnel *tunnel,
6257df37ff3SCatalin\(ux\) M. BOIE 	const struct in6_addr *v6dst)
6267df37ff3SCatalin\(ux\) M. BOIE {
6277df37ff3SCatalin\(ux\) M. BOIE 	int prefix_len;
6287df37ff3SCatalin\(ux\) M. BOIE 
6297df37ff3SCatalin\(ux\) M. BOIE #ifdef CONFIG_IPV6_SIT_6RD
6307df37ff3SCatalin\(ux\) M. BOIE 	prefix_len = tunnel->ip6rd.prefixlen + 32
6317df37ff3SCatalin\(ux\) M. BOIE 		- tunnel->ip6rd.relay_prefixlen;
6327df37ff3SCatalin\(ux\) M. BOIE #else
6337df37ff3SCatalin\(ux\) M. BOIE 	prefix_len = 48;
6347df37ff3SCatalin\(ux\) M. BOIE #endif
6357df37ff3SCatalin\(ux\) M. BOIE 	return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev);
6367df37ff3SCatalin\(ux\) M. BOIE }
6377df37ff3SCatalin\(ux\) M. BOIE 
6387df37ff3SCatalin\(ux\) M. BOIE /* Returns true if a packet is spoofed */
packet_is_spoofed(struct sk_buff * skb,const struct iphdr * iph,struct ip_tunnel * tunnel)6397df37ff3SCatalin\(ux\) M. BOIE static bool packet_is_spoofed(struct sk_buff *skb,
6407df37ff3SCatalin\(ux\) M. BOIE 			      const struct iphdr *iph,
6417df37ff3SCatalin\(ux\) M. BOIE 			      struct ip_tunnel *tunnel)
6427df37ff3SCatalin\(ux\) M. BOIE {
6437df37ff3SCatalin\(ux\) M. BOIE 	const struct ipv6hdr *ipv6h;
6447df37ff3SCatalin\(ux\) M. BOIE 
6457df37ff3SCatalin\(ux\) M. BOIE 	if (tunnel->dev->priv_flags & IFF_ISATAP) {
6467df37ff3SCatalin\(ux\) M. BOIE 		if (!isatap_chksrc(skb, iph, tunnel))
6477df37ff3SCatalin\(ux\) M. BOIE 			return true;
6487df37ff3SCatalin\(ux\) M. BOIE 
6497df37ff3SCatalin\(ux\) M. BOIE 		return false;
6507df37ff3SCatalin\(ux\) M. BOIE 	}
6517df37ff3SCatalin\(ux\) M. BOIE 
6527df37ff3SCatalin\(ux\) M. BOIE 	if (tunnel->dev->flags & IFF_POINTOPOINT)
6537df37ff3SCatalin\(ux\) M. BOIE 		return false;
6547df37ff3SCatalin\(ux\) M. BOIE 
6557df37ff3SCatalin\(ux\) M. BOIE 	ipv6h = ipv6_hdr(skb);
6567df37ff3SCatalin\(ux\) M. BOIE 
6577df37ff3SCatalin\(ux\) M. BOIE 	if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) {
6587df37ff3SCatalin\(ux\) M. BOIE 		net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
6597df37ff3SCatalin\(ux\) M. BOIE 				     &iph->saddr, &ipv6h->saddr,
6607df37ff3SCatalin\(ux\) M. BOIE 				     &iph->daddr, &ipv6h->daddr);
6617df37ff3SCatalin\(ux\) M. BOIE 		return true;
6627df37ff3SCatalin\(ux\) M. BOIE 	}
6637df37ff3SCatalin\(ux\) M. BOIE 
6647df37ff3SCatalin\(ux\) M. BOIE 	if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr)))
6657df37ff3SCatalin\(ux\) M. BOIE 		return false;
6667df37ff3SCatalin\(ux\) M. BOIE 
6677df37ff3SCatalin\(ux\) M. BOIE 	if (only_dnatted(tunnel, &ipv6h->daddr))
6687df37ff3SCatalin\(ux\) M. BOIE 		return false;
6697df37ff3SCatalin\(ux\) M. BOIE 
6707df37ff3SCatalin\(ux\) M. BOIE 	net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
6717df37ff3SCatalin\(ux\) M. BOIE 			     &iph->saddr, &ipv6h->saddr,
6727df37ff3SCatalin\(ux\) M. BOIE 			     &iph->daddr, &ipv6h->daddr);
6737df37ff3SCatalin\(ux\) M. BOIE 	return true;
6747df37ff3SCatalin\(ux\) M. BOIE }
6757df37ff3SCatalin\(ux\) M. BOIE 
ipip6_rcv(struct sk_buff * skb)6761da177e4SLinus Torvalds static int ipip6_rcv(struct sk_buff *skb)
6771da177e4SLinus Torvalds {
6781ad759d8SHannes Frederic Sowa 	const struct iphdr *iph = ip_hdr(skb);
6791da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
6803051fbecSDavid Ahern 	int sifindex;
681f4e0b4c5SNicolas Dichtel 	int err;
6821da177e4SLinus Torvalds 
6833051fbecSDavid Ahern 	sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0;
6844fddbf5dSSascha Hlusiak 	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
6853051fbecSDavid Ahern 				     iph->saddr, iph->daddr, sifindex);
68653b24b8fSIan Morris 	if (tunnel) {
68732b8a8e5SNicolas Dichtel 		if (tunnel->parms.iph.protocol != IPPROTO_IPV6 &&
68832b8a8e5SNicolas Dichtel 		    tunnel->parms.iph.protocol != 0)
68932b8a8e5SNicolas Dichtel 			goto out;
69032b8a8e5SNicolas Dichtel 
691b0e380b1SArnaldo Carvalho de Melo 		skb->mac_header = skb->network_header;
692c1d2bbe1SArnaldo Carvalho de Melo 		skb_reset_network_header(skb);
6938cdfab8aSPatrick McHardy 		IPCB(skb)->flags = 0;
694a09a4c8dSJesse Gross 		skb->dev = tunnel->dev;
695c7dc89c0SFred L. Templin 
6967df37ff3SCatalin\(ux\) M. BOIE 		if (packet_is_spoofed(skb, iph, tunnel)) {
697cb34b7cfSEric Dumazet 			DEV_STATS_INC(tunnel->dev, rx_errors);
698f4e0b4c5SNicolas Dichtel 			goto out;
699f4e0b4c5SNicolas Dichtel 		}
700f4e0b4c5SNicolas Dichtel 
701a09a4c8dSJesse Gross 		if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6),
702a09a4c8dSJesse Gross 		    !net_eq(tunnel->net, dev_net(tunnel->dev))))
703a09a4c8dSJesse Gross 			goto out;
704f4e0b4c5SNicolas Dichtel 
705bb9bd814SLorenzo Bianconi 		/* skb can be uncloned in iptunnel_pull_header, so
706bb9bd814SLorenzo Bianconi 		 * old iph is no longer valid
707bb9bd814SLorenzo Bianconi 		 */
708bb9bd814SLorenzo Bianconi 		iph = (const struct iphdr *)skb_mac_header(skb);
709730eed27SGuillaume Nault 		skb_reset_mac_header(skb);
710730eed27SGuillaume Nault 
711f4e0b4c5SNicolas Dichtel 		err = IP_ECN_decapsulate(iph, skb);
712f4e0b4c5SNicolas Dichtel 		if (unlikely(err)) {
713f4e0b4c5SNicolas Dichtel 			if (log_ecn_error)
714f4e0b4c5SNicolas Dichtel 				net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
715f4e0b4c5SNicolas Dichtel 						     &iph->saddr, iph->tos);
716f4e0b4c5SNicolas Dichtel 			if (err > 1) {
717cb34b7cfSEric Dumazet 				DEV_STATS_INC(tunnel->dev, rx_frame_errors);
718cb34b7cfSEric Dumazet 				DEV_STATS_INC(tunnel->dev, rx_errors);
719f4e0b4c5SNicolas Dichtel 				goto out;
720f4e0b4c5SNicolas Dichtel 			}
721c7dc89c0SFred L. Templin 		}
722d19d56ddSEric Dumazet 
7233a960ca7SEric Dumazet 		dev_sw_netstats_rx_add(tunnel->dev, skb->len);
72415fc1f70SEric Dumazet 
725caf586e5SEric Dumazet 		netif_rx(skb);
7268990f468SEric Dumazet 
7271da177e4SLinus Torvalds 		return 0;
7281da177e4SLinus Torvalds 	}
7291da177e4SLinus Torvalds 
7306dcdd1b3SDavid McCullough 	/* no tunnel matched,  let upstream know, ipsec may handle it */
7316dcdd1b3SDavid McCullough 	return 1;
7321da177e4SLinus Torvalds out:
73336ca34ccSDavid S. Miller 	kfree_skb(skb);
7341da177e4SLinus Torvalds 	return 0;
7351da177e4SLinus Torvalds }
7361da177e4SLinus Torvalds 
73749dbe7aeSSimon Horman static const struct tnl_ptk_info ipip_tpi = {
73832b8a8e5SNicolas Dichtel 	/* no tunnel info required for ipip. */
73932b8a8e5SNicolas Dichtel 	.proto = htons(ETH_P_IP),
74032b8a8e5SNicolas Dichtel };
74132b8a8e5SNicolas Dichtel 
74249dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
74349dbe7aeSSimon Horman static const struct tnl_ptk_info mplsip_tpi = {
74449dbe7aeSSimon Horman 	/* no tunnel info required for mplsip. */
74549dbe7aeSSimon Horman 	.proto = htons(ETH_P_MPLS_UC),
74649dbe7aeSSimon Horman };
74749dbe7aeSSimon Horman #endif
74849dbe7aeSSimon Horman 
sit_tunnel_rcv(struct sk_buff * skb,u8 ipproto)74949dbe7aeSSimon Horman static int sit_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
75032b8a8e5SNicolas Dichtel {
7513d7b46cdSPravin B Shelar 	const struct iphdr *iph;
75232b8a8e5SNicolas Dichtel 	struct ip_tunnel *tunnel;
7533051fbecSDavid Ahern 	int sifindex;
7543051fbecSDavid Ahern 
7553051fbecSDavid Ahern 	sifindex = netif_is_l3_master(skb->dev) ? IPCB(skb)->iif : 0;
75632b8a8e5SNicolas Dichtel 
7573d7b46cdSPravin B Shelar 	iph = ip_hdr(skb);
75832b8a8e5SNicolas Dichtel 	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
7593051fbecSDavid Ahern 				     iph->saddr, iph->daddr, sifindex);
76053b24b8fSIan Morris 	if (tunnel) {
76149dbe7aeSSimon Horman 		const struct tnl_ptk_info *tpi;
76249dbe7aeSSimon Horman 
76349dbe7aeSSimon Horman 		if (tunnel->parms.iph.protocol != ipproto &&
76432b8a8e5SNicolas Dichtel 		    tunnel->parms.iph.protocol != 0)
76532b8a8e5SNicolas Dichtel 			goto drop;
76632b8a8e5SNicolas Dichtel 
76732b8a8e5SNicolas Dichtel 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
76832b8a8e5SNicolas Dichtel 			goto drop;
76949dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
77049dbe7aeSSimon Horman 		if (ipproto == IPPROTO_MPLS)
77149dbe7aeSSimon Horman 			tpi = &mplsip_tpi;
77249dbe7aeSSimon Horman 		else
77349dbe7aeSSimon Horman #endif
77449dbe7aeSSimon Horman 			tpi = &ipip_tpi;
77549dbe7aeSSimon Horman 		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
776737e828bSLi Hongjun 			goto drop;
777730eed27SGuillaume Nault 		skb_reset_mac_header(skb);
778730eed27SGuillaume Nault 
77949dbe7aeSSimon Horman 		return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
78032b8a8e5SNicolas Dichtel 	}
78132b8a8e5SNicolas Dichtel 
78232b8a8e5SNicolas Dichtel 	return 1;
78332b8a8e5SNicolas Dichtel 
78432b8a8e5SNicolas Dichtel drop:
78532b8a8e5SNicolas Dichtel 	kfree_skb(skb);
78632b8a8e5SNicolas Dichtel 	return 0;
78732b8a8e5SNicolas Dichtel }
78832b8a8e5SNicolas Dichtel 
ipip_rcv(struct sk_buff * skb)78949dbe7aeSSimon Horman static int ipip_rcv(struct sk_buff *skb)
79049dbe7aeSSimon Horman {
79149dbe7aeSSimon Horman 	return sit_tunnel_rcv(skb, IPPROTO_IPIP);
79249dbe7aeSSimon Horman }
79349dbe7aeSSimon Horman 
79449dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
mplsip_rcv(struct sk_buff * skb)79549dbe7aeSSimon Horman static int mplsip_rcv(struct sk_buff *skb)
79649dbe7aeSSimon Horman {
79749dbe7aeSSimon Horman 	return sit_tunnel_rcv(skb, IPPROTO_MPLS);
79849dbe7aeSSimon Horman }
79949dbe7aeSSimon Horman #endif
80049dbe7aeSSimon Horman 
801fa857afcSYOSHIFUJI Hideaki / 吉藤英明 /*
802218774dcSHannes Frederic Sowa  * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function
803218774dcSHannes Frederic Sowa  * stores the embedded IPv4 address in v4dst and returns true.
804fa857afcSYOSHIFUJI Hideaki / 吉藤英明  */
check_6rd(struct ip_tunnel * tunnel,const struct in6_addr * v6dst,__be32 * v4dst)805218774dcSHannes Frederic Sowa static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst,
806218774dcSHannes Frederic Sowa 		      __be32 *v4dst)
8071da177e4SLinus Torvalds {
808fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #ifdef CONFIG_IPV6_SIT_6RD
809fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
810fa857afcSYOSHIFUJI Hideaki / 吉藤英明 			      tunnel->ip6rd.prefixlen)) {
8113a43be3cSEric Dumazet 		unsigned int pbw0, pbi0;
812fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		int pbi1;
813fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		u32 d;
814fa857afcSYOSHIFUJI Hideaki / 吉藤英明 
815fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		pbw0 = tunnel->ip6rd.prefixlen >> 5;
816fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		pbi0 = tunnel->ip6rd.prefixlen & 0x1f;
817fa857afcSYOSHIFUJI Hideaki / 吉藤英明 
818a843dc4eSMiaohe Lin 		d = tunnel->ip6rd.relay_prefixlen < 32 ?
819a843dc4eSMiaohe Lin 			(ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >>
820a843dc4eSMiaohe Lin 		    tunnel->ip6rd.relay_prefixlen : 0;
821fa857afcSYOSHIFUJI Hideaki / 吉藤英明 
822fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen;
823fa857afcSYOSHIFUJI Hideaki / 吉藤英明 		if (pbi1 > 0)
824e7db38c3SYOSHIFUJI Hideaki / 吉藤英明 			d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >>
825fa857afcSYOSHIFUJI Hideaki / 吉藤英明 			     (32 - pbi1);
826fa857afcSYOSHIFUJI Hideaki / 吉藤英明 
827218774dcSHannes Frederic Sowa 		*v4dst = tunnel->ip6rd.relay_prefix | htonl(d);
828218774dcSHannes Frederic Sowa 		return true;
829fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	}
830fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #else
8311da177e4SLinus Torvalds 	if (v6dst->s6_addr16[0] == htons(0x2002)) {
8321da177e4SLinus Torvalds 		/* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
833218774dcSHannes Frederic Sowa 		memcpy(v4dst, &v6dst->s6_addr16[1], 4);
834218774dcSHannes Frederic Sowa 		return true;
8351da177e4SLinus Torvalds 	}
836fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #endif
837218774dcSHannes Frederic Sowa 	return false;
838218774dcSHannes Frederic Sowa }
839218774dcSHannes Frederic Sowa 
try_6rd(struct ip_tunnel * tunnel,const struct in6_addr * v6dst)840218774dcSHannes Frederic Sowa static inline __be32 try_6rd(struct ip_tunnel *tunnel,
841218774dcSHannes Frederic Sowa 			     const struct in6_addr *v6dst)
842218774dcSHannes Frederic Sowa {
843218774dcSHannes Frederic Sowa 	__be32 dst = 0;
844218774dcSHannes Frederic Sowa 	check_6rd(tunnel, v6dst, &dst);
8451da177e4SLinus Torvalds 	return dst;
8461da177e4SLinus Torvalds }
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds /*
8491da177e4SLinus Torvalds  *	This function assumes it is being called from dev_queue_xmit()
8501da177e4SLinus Torvalds  *	and that skb is filled properly by that function.
8511da177e4SLinus Torvalds  */
8521da177e4SLinus Torvalds 
ipip6_tunnel_xmit(struct sk_buff * skb,struct net_device * dev)8536fef4c0cSStephen Hemminger static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
8546fef4c0cSStephen Hemminger 				     struct net_device *dev)
8551da177e4SLinus Torvalds {
8562941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
857b71d1d42SEric Dumazet 	const struct iphdr  *tiph = &tunnel->parms.iph;
858b71d1d42SEric Dumazet 	const struct ipv6hdr *iph6 = ipv6_hdr(skb);
8591da177e4SLinus Torvalds 	u8     tos = tunnel->parms.iph.tos;
860292f4f3cSHerbert Xu 	__be16 df = tiph->frag_off;
8611da177e4SLinus Torvalds 	struct rtable *rt;		/* Route to the other host */
8621da177e4SLinus Torvalds 	struct net_device *tdev;	/* Device to other host */
863c2636b4dSChuck Lever 	unsigned int max_headroom;	/* The extra header space needed */
864e69a4adcSAl Viro 	__be32 dst = tiph->daddr;
86531e4543dSDavid S. Miller 	struct flowi4 fl4;
8661da177e4SLinus Torvalds 	int    mtu;
867b71d1d42SEric Dumazet 	const struct in6_addr *addr6;
8681da177e4SLinus Torvalds 	int addr_type;
8690e6fbc5bSPravin B Shelar 	u8 ttl;
87014909664STom Herbert 	u8 protocol = IPPROTO_IPV6;
87114909664STom Herbert 	int t_hlen = tunnel->hlen + sizeof(struct iphdr);
8721da177e4SLinus Torvalds 
873c2bceb3dSLionel Elie Mamane 	if (tos == 1)
874c2bceb3dSLionel Elie Mamane 		tos = ipv6_get_dsfield(iph6);
875c2bceb3dSLionel Elie Mamane 
876c7dc89c0SFred L. Templin 	/* ISATAP (RFC4214) - must come before 6to4 */
877c7dc89c0SFred L. Templin 	if (dev->priv_flags & IFF_ISATAP) {
878c7dc89c0SFred L. Templin 		struct neighbour *neigh = NULL;
8791e2927b0SDavid S. Miller 		bool do_tx_error = false;
880c7dc89c0SFred L. Templin 
881adf30907SEric Dumazet 		if (skb_dst(skb))
8821e2927b0SDavid S. Miller 			neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
883c7dc89c0SFred L. Templin 
88463159f29SIan Morris 		if (!neigh) {
8857df37ff3SCatalin\(ux\) M. BOIE 			net_dbg_ratelimited("nexthop == NULL\n");
886c7dc89c0SFred L. Templin 			goto tx_error;
887c7dc89c0SFred L. Templin 		}
888c7dc89c0SFred L. Templin 
889b71d1d42SEric Dumazet 		addr6 = (const struct in6_addr *)&neigh->primary_key;
890c7dc89c0SFred L. Templin 		addr_type = ipv6_addr_type(addr6);
891c7dc89c0SFred L. Templin 
892c7dc89c0SFred L. Templin 		if ((addr_type & IPV6_ADDR_UNICAST) &&
893c7dc89c0SFred L. Templin 		     ipv6_addr_is_isatap(addr6))
894c7dc89c0SFred L. Templin 			dst = addr6->s6_addr32[3];
895c7dc89c0SFred L. Templin 		else
8961e2927b0SDavid S. Miller 			do_tx_error = true;
8971e2927b0SDavid S. Miller 
8981e2927b0SDavid S. Miller 		neigh_release(neigh);
8991e2927b0SDavid S. Miller 		if (do_tx_error)
900c7dc89c0SFred L. Templin 			goto tx_error;
901c7dc89c0SFred L. Templin 	}
902c7dc89c0SFred L. Templin 
9031da177e4SLinus Torvalds 	if (!dst)
904218774dcSHannes Frederic Sowa 		dst = try_6rd(tunnel, &iph6->daddr);
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds 	if (!dst) {
9071da177e4SLinus Torvalds 		struct neighbour *neigh = NULL;
9081e2927b0SDavid S. Miller 		bool do_tx_error = false;
9091da177e4SLinus Torvalds 
910adf30907SEric Dumazet 		if (skb_dst(skb))
9111e2927b0SDavid S. Miller 			neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
9121da177e4SLinus Torvalds 
91363159f29SIan Morris 		if (!neigh) {
9147df37ff3SCatalin\(ux\) M. BOIE 			net_dbg_ratelimited("nexthop == NULL\n");
9151da177e4SLinus Torvalds 			goto tx_error;
9161da177e4SLinus Torvalds 		}
9171da177e4SLinus Torvalds 
918b71d1d42SEric Dumazet 		addr6 = (const struct in6_addr *)&neigh->primary_key;
9191da177e4SLinus Torvalds 		addr_type = ipv6_addr_type(addr6);
9201da177e4SLinus Torvalds 
9211da177e4SLinus Torvalds 		if (addr_type == IPV6_ADDR_ANY) {
9220660e03fSArnaldo Carvalho de Melo 			addr6 = &ipv6_hdr(skb)->daddr;
9231da177e4SLinus Torvalds 			addr_type = ipv6_addr_type(addr6);
9241da177e4SLinus Torvalds 		}
9251da177e4SLinus Torvalds 
9261e2927b0SDavid S. Miller 		if ((addr_type & IPV6_ADDR_COMPATv4) != 0)
9271da177e4SLinus Torvalds 			dst = addr6->s6_addr32[3];
9281e2927b0SDavid S. Miller 		else
9291e2927b0SDavid S. Miller 			do_tx_error = true;
9301e2927b0SDavid S. Miller 
9311e2927b0SDavid S. Miller 		neigh_release(neigh);
9321e2927b0SDavid S. Miller 		if (do_tx_error)
9331e2927b0SDavid S. Miller 			goto tx_error;
9341da177e4SLinus Torvalds 	}
9351da177e4SLinus Torvalds 
9369830ad4cSCraig Gallek 	flowi4_init_output(&fl4, tunnel->parms.link, tunnel->fwmark,
9379830ad4cSCraig Gallek 			   RT_TOS(tos), RT_SCOPE_UNIVERSE, IPPROTO_IPV6,
9389830ad4cSCraig Gallek 			   0, dst, tiph->saddr, 0, 0,
9399830ad4cSCraig Gallek 			   sock_net_uid(tunnel->net, NULL));
9409830ad4cSCraig Gallek 
9416e3d1bbbSHaishuang Yan 	rt = dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr);
9426e3d1bbbSHaishuang Yan 	if (!rt) {
9436e3d1bbbSHaishuang Yan 		rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
944b23dd4feSDavid S. Miller 		if (IS_ERR(rt)) {
945cb34b7cfSEric Dumazet 			DEV_STATS_INC(dev, tx_carrier_errors);
9461da177e4SLinus Torvalds 			goto tx_error_icmp;
9471da177e4SLinus Torvalds 		}
9486e3d1bbbSHaishuang Yan 		dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr);
9496e3d1bbbSHaishuang Yan 	}
9506e3d1bbbSHaishuang Yan 
951ed6ae5caSIgnat Korchagin 	if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
9521da177e4SLinus Torvalds 		ip_rt_put(rt);
953cb34b7cfSEric Dumazet 		DEV_STATS_INC(dev, tx_carrier_errors);
9541da177e4SLinus Torvalds 		goto tx_error_icmp;
9551da177e4SLinus Torvalds 	}
956d8d1f30bSChangli Gao 	tdev = rt->dst.dev;
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 	if (tdev == dev) {
9591da177e4SLinus Torvalds 		ip_rt_put(rt);
960cb34b7cfSEric Dumazet 		DEV_STATS_INC(dev, collisions);
9611da177e4SLinus Torvalds 		goto tx_error;
9621da177e4SLinus Torvalds 	}
9631da177e4SLinus Torvalds 
9647e13318dSTom Herbert 	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) {
96514909664STom Herbert 		ip_rt_put(rt);
966aed069dfSAlexander Duyck 		goto tx_error;
96714909664STom Herbert 	}
96814909664STom Herbert 
969292f4f3cSHerbert Xu 	if (df) {
97014909664STom Herbert 		mtu = dst_mtu(&rt->dst) - t_hlen;
9711da177e4SLinus Torvalds 
9727f0e869cSzhang kai 		if (mtu < IPV4_MIN_MTU) {
973cb34b7cfSEric Dumazet 			DEV_STATS_INC(dev, collisions);
9741da177e4SLinus Torvalds 			ip_rt_put(rt);
9751da177e4SLinus Torvalds 			goto tx_error;
9761da177e4SLinus Torvalds 		}
977292f4f3cSHerbert Xu 
978292f4f3cSHerbert Xu 		if (mtu < IPV6_MIN_MTU) {
9791da177e4SLinus Torvalds 			mtu = IPV6_MIN_MTU;
980292f4f3cSHerbert Xu 			df = 0;
981292f4f3cSHerbert Xu 		}
982292f4f3cSHerbert Xu 
983f15ca723SNicolas Dichtel 		if (tunnel->parms.iph.daddr)
9844d42df46SHangbin Liu 			skb_dst_update_pmtu_no_confirm(skb, mtu);
9851da177e4SLinus Torvalds 
98658a47824SEric Dumazet 		if (skb->len > mtu && !skb_is_gso(skb)) {
9874372339eSJason A. Donenfeld 			icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
9881da177e4SLinus Torvalds 			ip_rt_put(rt);
9891da177e4SLinus Torvalds 			goto tx_error;
9901da177e4SLinus Torvalds 		}
991292f4f3cSHerbert Xu 	}
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds 	if (tunnel->err_count > 0) {
994bb80087aSWei Yongjun 		if (time_before(jiffies,
995bb80087aSWei Yongjun 				tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
9961da177e4SLinus Torvalds 			tunnel->err_count--;
9971da177e4SLinus Torvalds 			dst_link_failure(skb);
9981da177e4SLinus Torvalds 		} else
9991da177e4SLinus Torvalds 			tunnel->err_count = 0;
10001da177e4SLinus Torvalds 	}
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds 	/*
10031da177e4SLinus Torvalds 	 * Okay, now see if we can stuff it in the buffer as-is.
10041da177e4SLinus Torvalds 	 */
100514909664STom Herbert 	max_headroom = LL_RESERVED_SPACE(tdev) + t_hlen;
10061da177e4SLinus Torvalds 
1007cfbba49dSPatrick McHardy 	if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
1008cfbba49dSPatrick McHardy 	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
10091da177e4SLinus Torvalds 		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
10101da177e4SLinus Torvalds 		if (!new_skb) {
10111da177e4SLinus Torvalds 			ip_rt_put(rt);
1012cb34b7cfSEric Dumazet 			DEV_STATS_INC(dev, tx_dropped);
101366028310SGao feng 			kfree_skb(skb);
10146ed10654SPatrick McHardy 			return NETDEV_TX_OK;
10151da177e4SLinus Torvalds 		}
10161da177e4SLinus Torvalds 		if (skb->sk)
10171da177e4SLinus Torvalds 			skb_set_owner_w(new_skb, skb->sk);
10181da177e4SLinus Torvalds 		dev_kfree_skb(skb);
10191da177e4SLinus Torvalds 		skb = new_skb;
10200660e03fSArnaldo Carvalho de Melo 		iph6 = ipv6_hdr(skb);
10211da177e4SLinus Torvalds 	}
10220e6fbc5bSPravin B Shelar 	ttl = tiph->ttl;
10230e6fbc5bSPravin B Shelar 	if (ttl == 0)
10240e6fbc5bSPravin B Shelar 		ttl = iph6->hop_limit;
10250e6fbc5bSPravin B Shelar 	tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
10261da177e4SLinus Torvalds 
1027ac931d4cSChristian Ehrig 	if (ip_tunnel_encap(skb, &tunnel->encap, &protocol, &fl4) < 0) {
10286a9eadccSLi RongQing 		ip_rt_put(rt);
102914909664STom Herbert 		goto tx_error;
10306a9eadccSLi RongQing 	}
10313d483058SHannes Frederic Sowa 
1032469471cdSTom Herbert 	skb_set_inner_ipproto(skb, IPPROTO_IPV6);
1033469471cdSTom Herbert 
1034039f5062SPravin B Shelar 	iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
1035039f5062SPravin B Shelar 		      df, !net_eq(tunnel->net, dev_net(dev)));
10366ed10654SPatrick McHardy 	return NETDEV_TX_OK;
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds tx_error_icmp:
10391da177e4SLinus Torvalds 	dst_link_failure(skb);
10401da177e4SLinus Torvalds tx_error:
104166028310SGao feng 	kfree_skb(skb);
1042cb34b7cfSEric Dumazet 	DEV_STATS_INC(dev, tx_errors);
10436ed10654SPatrick McHardy 	return NETDEV_TX_OK;
10441da177e4SLinus Torvalds }
10451da177e4SLinus Torvalds 
sit_tunnel_xmit__(struct sk_buff * skb,struct net_device * dev,u8 ipproto)104649dbe7aeSSimon Horman static netdev_tx_t sit_tunnel_xmit__(struct sk_buff *skb,
104749dbe7aeSSimon Horman 				     struct net_device *dev, u8 ipproto)
104832b8a8e5SNicolas Dichtel {
104932b8a8e5SNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
105032b8a8e5SNicolas Dichtel 	const struct iphdr  *tiph = &tunnel->parms.iph;
105132b8a8e5SNicolas Dichtel 
10527e13318dSTom Herbert 	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
1053aed069dfSAlexander Duyck 		goto tx_error;
105432b8a8e5SNicolas Dichtel 
105549dbe7aeSSimon Horman 	skb_set_inner_ipproto(skb, ipproto);
1056469471cdSTom Herbert 
105749dbe7aeSSimon Horman 	ip_tunnel_xmit(skb, dev, tiph, ipproto);
105832b8a8e5SNicolas Dichtel 	return NETDEV_TX_OK;
1059aed069dfSAlexander Duyck tx_error:
1060aed069dfSAlexander Duyck 	kfree_skb(skb);
1061cb34b7cfSEric Dumazet 	DEV_STATS_INC(dev, tx_errors);
106261c1db7fSEric Dumazet 	return NETDEV_TX_OK;
106332b8a8e5SNicolas Dichtel }
106432b8a8e5SNicolas Dichtel 
sit_tunnel_xmit(struct sk_buff * skb,struct net_device * dev)106532b8a8e5SNicolas Dichtel static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb,
106632b8a8e5SNicolas Dichtel 				   struct net_device *dev)
106732b8a8e5SNicolas Dichtel {
1068cb9f1b78SWillem de Bruijn 	if (!pskb_inet_may_pull(skb))
1069cb9f1b78SWillem de Bruijn 		goto tx_err;
1070cb9f1b78SWillem de Bruijn 
107132b8a8e5SNicolas Dichtel 	switch (skb->protocol) {
107232b8a8e5SNicolas Dichtel 	case htons(ETH_P_IP):
107349dbe7aeSSimon Horman 		sit_tunnel_xmit__(skb, dev, IPPROTO_IPIP);
107432b8a8e5SNicolas Dichtel 		break;
107532b8a8e5SNicolas Dichtel 	case htons(ETH_P_IPV6):
107632b8a8e5SNicolas Dichtel 		ipip6_tunnel_xmit(skb, dev);
107732b8a8e5SNicolas Dichtel 		break;
107849dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
107949dbe7aeSSimon Horman 	case htons(ETH_P_MPLS_UC):
108049dbe7aeSSimon Horman 		sit_tunnel_xmit__(skb, dev, IPPROTO_MPLS);
108149dbe7aeSSimon Horman 		break;
108249dbe7aeSSimon Horman #endif
108332b8a8e5SNicolas Dichtel 	default:
108432b8a8e5SNicolas Dichtel 		goto tx_err;
108532b8a8e5SNicolas Dichtel 	}
108632b8a8e5SNicolas Dichtel 
108732b8a8e5SNicolas Dichtel 	return NETDEV_TX_OK;
108832b8a8e5SNicolas Dichtel 
108932b8a8e5SNicolas Dichtel tx_err:
1090cb34b7cfSEric Dumazet 	DEV_STATS_INC(dev, tx_errors);
109166028310SGao feng 	kfree_skb(skb);
109232b8a8e5SNicolas Dichtel 	return NETDEV_TX_OK;
109332b8a8e5SNicolas Dichtel 
109432b8a8e5SNicolas Dichtel }
109532b8a8e5SNicolas Dichtel 
ipip6_tunnel_bind_dev(struct net_device * dev)10968a4a50f9SMichal Schmidt static void ipip6_tunnel_bind_dev(struct net_device *dev)
10978a4a50f9SMichal Schmidt {
1098c88f8d5cSCong Wang 	struct ip_tunnel *tunnel = netdev_priv(dev);
1099c88f8d5cSCong Wang 	int t_hlen = tunnel->hlen + sizeof(struct iphdr);
11008a4a50f9SMichal Schmidt 	struct net_device *tdev = NULL;
1101c88f8d5cSCong Wang 	int hlen = LL_MAX_HEADER;
1102b71d1d42SEric Dumazet 	const struct iphdr *iph;
110331e4543dSDavid S. Miller 	struct flowi4 fl4;
11048a4a50f9SMichal Schmidt 
11058a4a50f9SMichal Schmidt 	iph = &tunnel->parms.iph;
11068a4a50f9SMichal Schmidt 
11078a4a50f9SMichal Schmidt 	if (iph->daddr) {
11085e6700b3SNicolas Dichtel 		struct rtable *rt = ip_route_output_ports(tunnel->net, &fl4,
11095e6700b3SNicolas Dichtel 							  NULL,
111078fbfd8aSDavid S. Miller 							  iph->daddr, iph->saddr,
111178fbfd8aSDavid S. Miller 							  0, 0,
111278fbfd8aSDavid S. Miller 							  IPPROTO_IPV6,
111378fbfd8aSDavid S. Miller 							  RT_TOS(iph->tos),
111478fbfd8aSDavid S. Miller 							  tunnel->parms.link);
1115b23dd4feSDavid S. Miller 
1116b23dd4feSDavid S. Miller 		if (!IS_ERR(rt)) {
1117d8d1f30bSChangli Gao 			tdev = rt->dst.dev;
11188a4a50f9SMichal Schmidt 			ip_rt_put(rt);
11198a4a50f9SMichal Schmidt 		}
11208a4a50f9SMichal Schmidt 		dev->flags |= IFF_POINTOPOINT;
11218a4a50f9SMichal Schmidt 	}
11228a4a50f9SMichal Schmidt 
11238a4a50f9SMichal Schmidt 	if (!tdev && tunnel->parms.link)
11245e6700b3SNicolas Dichtel 		tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link);
11258a4a50f9SMichal Schmidt 
1126ff6ab32bSStephen Suryaputra 	if (tdev && !netif_is_l3_master(tdev)) {
1127d89d7ff0SEric Dumazet 		int mtu;
112814909664STom Herbert 
1129d89d7ff0SEric Dumazet 		mtu = tdev->mtu - t_hlen;
1130d89d7ff0SEric Dumazet 		if (mtu < IPV6_MIN_MTU)
1131d89d7ff0SEric Dumazet 			mtu = IPV6_MIN_MTU;
1132d89d7ff0SEric Dumazet 		WRITE_ONCE(dev->mtu, mtu);
1133c88f8d5cSCong Wang 		hlen = tdev->hard_header_len + tdev->needed_headroom;
11348a4a50f9SMichal Schmidt 	}
1135c88f8d5cSCong Wang 	dev->needed_headroom = t_hlen + hlen;
11368a4a50f9SMichal Schmidt }
11378a4a50f9SMichal Schmidt 
ipip6_tunnel_update(struct ip_tunnel * t,struct ip_tunnel_parm * p,__u32 fwmark)11389830ad4cSCraig Gallek static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p,
11399830ad4cSCraig Gallek 				__u32 fwmark)
1140f3723416SNicolas Dichtel {
11415e6700b3SNicolas Dichtel 	struct net *net = t->net;
1142f3723416SNicolas Dichtel 	struct sit_net *sitn = net_generic(net, sit_net_id);
1143f3723416SNicolas Dichtel 
1144f3723416SNicolas Dichtel 	ipip6_tunnel_unlink(sitn, t);
1145f3723416SNicolas Dichtel 	synchronize_net();
1146f3723416SNicolas Dichtel 	t->parms.iph.saddr = p->iph.saddr;
1147f3723416SNicolas Dichtel 	t->parms.iph.daddr = p->iph.daddr;
11485a1b7e1aSJakub Kicinski 	__dev_addr_set(t->dev, &p->iph.saddr, 4);
1149f3723416SNicolas Dichtel 	memcpy(t->dev->broadcast, &p->iph.daddr, 4);
1150f3723416SNicolas Dichtel 	ipip6_tunnel_link(sitn, t);
1151f3723416SNicolas Dichtel 	t->parms.iph.ttl = p->iph.ttl;
1152f3723416SNicolas Dichtel 	t->parms.iph.tos = p->iph.tos;
1153f859b4afSHangbin Liu 	t->parms.iph.frag_off = p->iph.frag_off;
11549830ad4cSCraig Gallek 	if (t->parms.link != p->link || t->fwmark != fwmark) {
1155f3723416SNicolas Dichtel 		t->parms.link = p->link;
11569830ad4cSCraig Gallek 		t->fwmark = fwmark;
1157f3723416SNicolas Dichtel 		ipip6_tunnel_bind_dev(t->dev);
1158f3723416SNicolas Dichtel 	}
1159e09acddfSPaolo Abeni 	dst_cache_reset(&t->dst_cache);
1160f3723416SNicolas Dichtel 	netdev_state_change(t->dev);
1161f3723416SNicolas Dichtel }
1162f3723416SNicolas Dichtel 
1163e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
ipip6_tunnel_update_6rd(struct ip_tunnel * t,struct ip_tunnel_6rd * ip6rd)1164e2f1f072SNicolas Dichtel static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
1165e2f1f072SNicolas Dichtel 				   struct ip_tunnel_6rd *ip6rd)
1166e2f1f072SNicolas Dichtel {
1167e2f1f072SNicolas Dichtel 	struct in6_addr prefix;
1168e2f1f072SNicolas Dichtel 	__be32 relay_prefix;
1169e2f1f072SNicolas Dichtel 
1170e2f1f072SNicolas Dichtel 	if (ip6rd->relay_prefixlen > 32 ||
1171e2f1f072SNicolas Dichtel 	    ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64)
1172e2f1f072SNicolas Dichtel 		return -EINVAL;
1173e2f1f072SNicolas Dichtel 
1174e2f1f072SNicolas Dichtel 	ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen);
1175e2f1f072SNicolas Dichtel 	if (!ipv6_addr_equal(&prefix, &ip6rd->prefix))
1176e2f1f072SNicolas Dichtel 		return -EINVAL;
1177e2f1f072SNicolas Dichtel 	if (ip6rd->relay_prefixlen)
1178e2f1f072SNicolas Dichtel 		relay_prefix = ip6rd->relay_prefix &
1179e2f1f072SNicolas Dichtel 			       htonl(0xffffffffUL <<
1180e2f1f072SNicolas Dichtel 				     (32 - ip6rd->relay_prefixlen));
1181e2f1f072SNicolas Dichtel 	else
1182e2f1f072SNicolas Dichtel 		relay_prefix = 0;
1183e2f1f072SNicolas Dichtel 	if (relay_prefix != ip6rd->relay_prefix)
1184e2f1f072SNicolas Dichtel 		return -EINVAL;
1185e2f1f072SNicolas Dichtel 
1186e2f1f072SNicolas Dichtel 	t->ip6rd.prefix = prefix;
1187e2f1f072SNicolas Dichtel 	t->ip6rd.relay_prefix = relay_prefix;
1188e2f1f072SNicolas Dichtel 	t->ip6rd.prefixlen = ip6rd->prefixlen;
1189e2f1f072SNicolas Dichtel 	t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
1190e09acddfSPaolo Abeni 	dst_cache_reset(&t->dst_cache);
1191e2f1f072SNicolas Dichtel 	netdev_state_change(t->dev);
1192e2f1f072SNicolas Dichtel 	return 0;
1193e2f1f072SNicolas Dichtel }
1194fd5d687bSChristoph Hellwig 
1195fd5d687bSChristoph Hellwig static int
ipip6_tunnel_get6rd(struct net_device * dev,struct ip_tunnel_parm __user * data)11963e7a1c7cSArnd Bergmann ipip6_tunnel_get6rd(struct net_device *dev, struct ip_tunnel_parm __user *data)
1197fd5d687bSChristoph Hellwig {
1198fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
1199fd5d687bSChristoph Hellwig 	struct ip_tunnel_6rd ip6rd;
1200fd5d687bSChristoph Hellwig 	struct ip_tunnel_parm p;
1201fd5d687bSChristoph Hellwig 
1202fd5d687bSChristoph Hellwig 	if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
12033e7a1c7cSArnd Bergmann 		if (copy_from_user(&p, data, sizeof(p)))
1204fd5d687bSChristoph Hellwig 			return -EFAULT;
1205fd5d687bSChristoph Hellwig 		t = ipip6_tunnel_locate(t->net, &p, 0);
1206fd5d687bSChristoph Hellwig 	}
1207fd5d687bSChristoph Hellwig 	if (!t)
1208fd5d687bSChristoph Hellwig 		t = netdev_priv(dev);
1209fd5d687bSChristoph Hellwig 
1210fd5d687bSChristoph Hellwig 	ip6rd.prefix = t->ip6rd.prefix;
1211fd5d687bSChristoph Hellwig 	ip6rd.relay_prefix = t->ip6rd.relay_prefix;
1212fd5d687bSChristoph Hellwig 	ip6rd.prefixlen = t->ip6rd.prefixlen;
1213fd5d687bSChristoph Hellwig 	ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
12143e7a1c7cSArnd Bergmann 	if (copy_to_user(data, &ip6rd, sizeof(ip6rd)))
1215fd5d687bSChristoph Hellwig 		return -EFAULT;
1216fd5d687bSChristoph Hellwig 	return 0;
1217fd5d687bSChristoph Hellwig }
1218fd5d687bSChristoph Hellwig 
1219fd5d687bSChristoph Hellwig static int
ipip6_tunnel_6rdctl(struct net_device * dev,struct ip_tunnel_6rd __user * data,int cmd)12203e7a1c7cSArnd Bergmann ipip6_tunnel_6rdctl(struct net_device *dev, struct ip_tunnel_6rd __user *data,
12213e7a1c7cSArnd Bergmann 		    int cmd)
1222fd5d687bSChristoph Hellwig {
1223fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
1224fd5d687bSChristoph Hellwig 	struct ip_tunnel_6rd ip6rd;
1225fd5d687bSChristoph Hellwig 	int err;
1226fd5d687bSChristoph Hellwig 
1227fd5d687bSChristoph Hellwig 	if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
1228fd5d687bSChristoph Hellwig 		return -EPERM;
12293e7a1c7cSArnd Bergmann 	if (copy_from_user(&ip6rd, data, sizeof(ip6rd)))
1230fd5d687bSChristoph Hellwig 		return -EFAULT;
1231fd5d687bSChristoph Hellwig 
1232fd5d687bSChristoph Hellwig 	if (cmd != SIOCDEL6RD) {
1233fd5d687bSChristoph Hellwig 		err = ipip6_tunnel_update_6rd(t, &ip6rd);
1234fd5d687bSChristoph Hellwig 		if (err < 0)
1235fd5d687bSChristoph Hellwig 			return err;
1236fd5d687bSChristoph Hellwig 	} else
1237fd5d687bSChristoph Hellwig 		ipip6_tunnel_clone_6rd(dev, dev_to_sit_net(dev));
1238fd5d687bSChristoph Hellwig 	return 0;
1239fd5d687bSChristoph Hellwig }
1240fd5d687bSChristoph Hellwig 
1241fd5d687bSChristoph Hellwig #endif /* CONFIG_IPV6_SIT_6RD */
1242e2f1f072SNicolas Dichtel 
ipip6_valid_ip_proto(u8 ipproto)124303ff4979SWei Yongjun static bool ipip6_valid_ip_proto(u8 ipproto)
124449dbe7aeSSimon Horman {
124549dbe7aeSSimon Horman 	return ipproto == IPPROTO_IPV6 ||
124649dbe7aeSSimon Horman 		ipproto == IPPROTO_IPIP ||
124749dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
124849dbe7aeSSimon Horman 		ipproto == IPPROTO_MPLS ||
124949dbe7aeSSimon Horman #endif
125049dbe7aeSSimon Horman 		ipproto == 0;
125149dbe7aeSSimon Horman }
125249dbe7aeSSimon Horman 
12531da177e4SLinus Torvalds static int
__ipip6_tunnel_ioctl_validate(struct net * net,struct ip_tunnel_parm * p)1254fd5d687bSChristoph Hellwig __ipip6_tunnel_ioctl_validate(struct net *net, struct ip_tunnel_parm *p)
12551da177e4SLinus Torvalds {
1256fd5d687bSChristoph Hellwig 	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1257fd5d687bSChristoph Hellwig 		return -EPERM;
12581da177e4SLinus Torvalds 
1259fd5d687bSChristoph Hellwig 	if (!ipip6_valid_ip_proto(p->iph.protocol))
1260fd5d687bSChristoph Hellwig 		return -EINVAL;
1261fd5d687bSChristoph Hellwig 	if (p->iph.version != 4 ||
1262fd5d687bSChristoph Hellwig 	    p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)))
1263fd5d687bSChristoph Hellwig 		return -EINVAL;
1264fd5d687bSChristoph Hellwig 
1265fd5d687bSChristoph Hellwig 	if (p->iph.ttl)
1266fd5d687bSChristoph Hellwig 		p->iph.frag_off |= htons(IP_DF);
1267fd5d687bSChristoph Hellwig 	return 0;
12681da177e4SLinus Torvalds }
1269fd5d687bSChristoph Hellwig 
1270fd5d687bSChristoph Hellwig static int
ipip6_tunnel_get(struct net_device * dev,struct ip_tunnel_parm * p)1271f60fe2dfSChristoph Hellwig ipip6_tunnel_get(struct net_device *dev, struct ip_tunnel_parm *p)
1272fd5d687bSChristoph Hellwig {
1273fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
1274fd5d687bSChristoph Hellwig 
1275f60fe2dfSChristoph Hellwig 	if (dev == dev_to_sit_net(dev)->fb_tunnel_dev)
1276f60fe2dfSChristoph Hellwig 		t = ipip6_tunnel_locate(t->net, p, 0);
127763159f29SIan Morris 	if (!t)
12782941a486SPatrick McHardy 		t = netdev_priv(dev);
1279f60fe2dfSChristoph Hellwig 	memcpy(p, &t->parms, sizeof(*p));
1280fd5d687bSChristoph Hellwig 	return 0;
12819aad77c3SNicolas Dichtel }
1282fa857afcSYOSHIFUJI Hideaki / 吉藤英明 
1283fd5d687bSChristoph Hellwig static int
ipip6_tunnel_add(struct net_device * dev,struct ip_tunnel_parm * p)1284f60fe2dfSChristoph Hellwig ipip6_tunnel_add(struct net_device *dev, struct ip_tunnel_parm *p)
1285fd5d687bSChristoph Hellwig {
1286fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
1287fd5d687bSChristoph Hellwig 	int err;
12881da177e4SLinus Torvalds 
1289f60fe2dfSChristoph Hellwig 	err = __ipip6_tunnel_ioctl_validate(t->net, p);
1290fd5d687bSChristoph Hellwig 	if (err)
1291fd5d687bSChristoph Hellwig 		return err;
12921da177e4SLinus Torvalds 
1293f60fe2dfSChristoph Hellwig 	t = ipip6_tunnel_locate(t->net, p, 1);
1294fd5d687bSChristoph Hellwig 	if (!t)
1295fd5d687bSChristoph Hellwig 		return -ENOBUFS;
1296fd5d687bSChristoph Hellwig 	return 0;
12971da177e4SLinus Torvalds }
1298fd5d687bSChristoph Hellwig 
1299fd5d687bSChristoph Hellwig static int
ipip6_tunnel_change(struct net_device * dev,struct ip_tunnel_parm * p)1300f60fe2dfSChristoph Hellwig ipip6_tunnel_change(struct net_device *dev, struct ip_tunnel_parm *p)
1301fd5d687bSChristoph Hellwig {
1302fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
1303fd5d687bSChristoph Hellwig 	int err;
1304fd5d687bSChristoph Hellwig 
1305f60fe2dfSChristoph Hellwig 	err = __ipip6_tunnel_ioctl_validate(t->net, p);
1306fd5d687bSChristoph Hellwig 	if (err)
1307fd5d687bSChristoph Hellwig 		return err;
1308fd5d687bSChristoph Hellwig 
1309f60fe2dfSChristoph Hellwig 	t = ipip6_tunnel_locate(t->net, p, 0);
1310fd5d687bSChristoph Hellwig 	if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
1311fd5d687bSChristoph Hellwig 		if (!t)
1312fd5d687bSChristoph Hellwig 			return -ENOENT;
1313fd5d687bSChristoph Hellwig 	} else {
1314fd5d687bSChristoph Hellwig 		if (t) {
1315fd5d687bSChristoph Hellwig 			if (t->dev != dev)
1316fd5d687bSChristoph Hellwig 				return -EEXIST;
13171da177e4SLinus Torvalds 		} else {
1318f60fe2dfSChristoph Hellwig 			if (((dev->flags & IFF_POINTOPOINT) && !p->iph.daddr) ||
1319f60fe2dfSChristoph Hellwig 			    (!(dev->flags & IFF_POINTOPOINT) && p->iph.daddr))
1320fd5d687bSChristoph Hellwig 				return -EINVAL;
13212941a486SPatrick McHardy 			t = netdev_priv(dev);
1322f9cd5a55SNicolas Dichtel 		}
1323f9cd5a55SNicolas Dichtel 
1324f60fe2dfSChristoph Hellwig 		ipip6_tunnel_update(t, p, t->fwmark);
13258a4a50f9SMichal Schmidt 	}
1326f9cd5a55SNicolas Dichtel 
1327fd5d687bSChristoph Hellwig 	return 0;
1328fd5d687bSChristoph Hellwig }
13291da177e4SLinus Torvalds 
1330fd5d687bSChristoph Hellwig static int
ipip6_tunnel_del(struct net_device * dev,struct ip_tunnel_parm * p)1331f60fe2dfSChristoph Hellwig ipip6_tunnel_del(struct net_device *dev, struct ip_tunnel_parm *p)
1332fd5d687bSChristoph Hellwig {
1333fd5d687bSChristoph Hellwig 	struct ip_tunnel *t = netdev_priv(dev);
13341da177e4SLinus Torvalds 
1335fd5d687bSChristoph Hellwig 	if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
1336fd5d687bSChristoph Hellwig 		return -EPERM;
1337fd5d687bSChristoph Hellwig 
1338fd5d687bSChristoph Hellwig 	if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
1339f60fe2dfSChristoph Hellwig 		t = ipip6_tunnel_locate(t->net, p, 0);
134063159f29SIan Morris 		if (!t)
1341fd5d687bSChristoph Hellwig 			return -ENOENT;
1342fd5d687bSChristoph Hellwig 		if (t == netdev_priv(dev_to_sit_net(dev)->fb_tunnel_dev))
1343fd5d687bSChristoph Hellwig 			return -EPERM;
13441da177e4SLinus Torvalds 		dev = t->dev;
13451da177e4SLinus Torvalds 	}
134622f8cde5SStephen Hemminger 	unregister_netdevice(dev);
1347fd5d687bSChristoph Hellwig 	return 0;
1348300aaeeaSYOSHIFUJI Hideaki }
1349fadf6bf0STemplin, Fred L 
1350fd5d687bSChristoph Hellwig static int
ipip6_tunnel_ctl(struct net_device * dev,struct ip_tunnel_parm * p,int cmd)1351f60fe2dfSChristoph Hellwig ipip6_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
1352f60fe2dfSChristoph Hellwig {
1353f60fe2dfSChristoph Hellwig 	switch (cmd) {
1354f60fe2dfSChristoph Hellwig 	case SIOCGETTUNNEL:
1355f60fe2dfSChristoph Hellwig 		return ipip6_tunnel_get(dev, p);
1356f60fe2dfSChristoph Hellwig 	case SIOCADDTUNNEL:
1357f60fe2dfSChristoph Hellwig 		return ipip6_tunnel_add(dev, p);
1358f60fe2dfSChristoph Hellwig 	case SIOCCHGTUNNEL:
1359f60fe2dfSChristoph Hellwig 		return ipip6_tunnel_change(dev, p);
1360f60fe2dfSChristoph Hellwig 	case SIOCDELTUNNEL:
1361f60fe2dfSChristoph Hellwig 		return ipip6_tunnel_del(dev, p);
1362f60fe2dfSChristoph Hellwig 	default:
1363f60fe2dfSChristoph Hellwig 		return -EINVAL;
1364f60fe2dfSChristoph Hellwig 	}
1365f60fe2dfSChristoph Hellwig }
1366f60fe2dfSChristoph Hellwig 
1367f60fe2dfSChristoph Hellwig static int
ipip6_tunnel_siocdevprivate(struct net_device * dev,struct ifreq * ifr,void __user * data,int cmd)13683e7a1c7cSArnd Bergmann ipip6_tunnel_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
13693e7a1c7cSArnd Bergmann 			    void __user *data, int cmd)
1370fd5d687bSChristoph Hellwig {
1371fd5d687bSChristoph Hellwig 	switch (cmd) {
1372fd5d687bSChristoph Hellwig 	case SIOCGETTUNNEL:
1373fd5d687bSChristoph Hellwig 	case SIOCADDTUNNEL:
1374fd5d687bSChristoph Hellwig 	case SIOCCHGTUNNEL:
1375fd5d687bSChristoph Hellwig 	case SIOCDELTUNNEL:
13763e7a1c7cSArnd Bergmann 		return ip_tunnel_siocdevprivate(dev, ifr, data, cmd);
1377fd5d687bSChristoph Hellwig 	case SIOCGETPRL:
13783e7a1c7cSArnd Bergmann 		return ipip6_tunnel_get_prl(dev, data);
1379fd5d687bSChristoph Hellwig 	case SIOCADDPRL:
1380fd5d687bSChristoph Hellwig 	case SIOCDELPRL:
1381fd5d687bSChristoph Hellwig 	case SIOCCHGPRL:
13823e7a1c7cSArnd Bergmann 		return ipip6_tunnel_prl_ctl(dev, data, cmd);
1383fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #ifdef CONFIG_IPV6_SIT_6RD
1384fd5d687bSChristoph Hellwig 	case SIOCGET6RD:
13853e7a1c7cSArnd Bergmann 		return ipip6_tunnel_get6rd(dev, data);
1386fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	case SIOCADD6RD:
1387fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	case SIOCCHG6RD:
1388fa857afcSYOSHIFUJI Hideaki / 吉藤英明 	case SIOCDEL6RD:
13893e7a1c7cSArnd Bergmann 		return ipip6_tunnel_6rdctl(dev, data, cmd);
1390fa857afcSYOSHIFUJI Hideaki / 吉藤英明 #endif
13911da177e4SLinus Torvalds 	default:
1392fd5d687bSChristoph Hellwig 		return -EINVAL;
13931da177e4SLinus Torvalds 	}
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds 
13961326c3d5SStephen Hemminger static const struct net_device_ops ipip6_netdev_ops = {
1397ebe084aaSSteffen Klassert 	.ndo_init	= ipip6_tunnel_init,
13981326c3d5SStephen Hemminger 	.ndo_uninit	= ipip6_tunnel_uninit,
139932b8a8e5SNicolas Dichtel 	.ndo_start_xmit	= sit_tunnel_xmit,
14003e7a1c7cSArnd Bergmann 	.ndo_siocdevprivate = ipip6_tunnel_siocdevprivate,
140198d7fc46SHeiner Kallweit 	.ndo_get_stats64 = dev_get_tstats64,
14021e99584bSNicolas Dichtel 	.ndo_get_iflink = ip_tunnel_get_iflink,
1403f60fe2dfSChristoph Hellwig 	.ndo_tunnel_ctl = ipip6_tunnel_ctl,
14041326c3d5SStephen Hemminger };
14051326c3d5SStephen Hemminger 
ipip6_dev_free(struct net_device * dev)140615fc1f70SEric Dumazet static void ipip6_dev_free(struct net_device *dev)
140715fc1f70SEric Dumazet {
1408cf71d2bcSNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
1409cf71d2bcSNicolas Dichtel 
1410e09acddfSPaolo Abeni 	dst_cache_destroy(&tunnel->dst_cache);
141115fc1f70SEric Dumazet 	free_percpu(dev->tstats);
141215fc1f70SEric Dumazet }
141315fc1f70SEric Dumazet 
141461c1db7fSEric Dumazet #define SIT_FEATURES (NETIF_F_SG	   | \
141561c1db7fSEric Dumazet 		      NETIF_F_FRAGLIST	   | \
141661c1db7fSEric Dumazet 		      NETIF_F_HIGHDMA	   | \
141761c1db7fSEric Dumazet 		      NETIF_F_GSO_SOFTWARE | \
141861c1db7fSEric Dumazet 		      NETIF_F_HW_CSUM)
141961c1db7fSEric Dumazet 
ipip6_tunnel_setup(struct net_device * dev)14201da177e4SLinus Torvalds static void ipip6_tunnel_setup(struct net_device *dev)
14211da177e4SLinus Torvalds {
142214909664STom Herbert 	struct ip_tunnel *tunnel = netdev_priv(dev);
142314909664STom Herbert 	int t_hlen = tunnel->hlen + sizeof(struct iphdr);
142414909664STom Herbert 
14251326c3d5SStephen Hemminger 	dev->netdev_ops		= &ipip6_netdev_ops;
142675ea1f47SJason A. Donenfeld 	dev->header_ops		= &ip_tunnel_header_ops;
1427cf124db5SDavid S. Miller 	dev->needs_free_netdev	= true;
1428cf124db5SDavid S. Miller 	dev->priv_destructor	= ipip6_dev_free;
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	dev->type		= ARPHRD_SIT;
143114909664STom Herbert 	dev->mtu		= ETH_DATA_LEN - t_hlen;
1432b96f9afeSJarod Wilson 	dev->min_mtu		= IPV6_MIN_MTU;
1433f7ff1fdeSNicolas Dichtel 	dev->max_mtu		= IP6_MAX_MTU - t_hlen;
14341da177e4SLinus Torvalds 	dev->flags		= IFF_NOARP;
143502875878SEric Dumazet 	netif_keep_dst(dev);
14361da177e4SLinus Torvalds 	dev->addr_len		= 4;
14378df40d10SEric Dumazet 	dev->features		|= NETIF_F_LLTX;
143861c1db7fSEric Dumazet 	dev->features		|= SIT_FEATURES;
143961c1db7fSEric Dumazet 	dev->hw_features	|= SIT_FEATURES;
14401da177e4SLinus Torvalds }
14411da177e4SLinus Torvalds 
ipip6_tunnel_init(struct net_device * dev)144215fc1f70SEric Dumazet static int ipip6_tunnel_init(struct net_device *dev)
14431da177e4SLinus Torvalds {
14441326c3d5SStephen Hemminger 	struct ip_tunnel *tunnel = netdev_priv(dev);
1445e09acddfSPaolo Abeni 	int err;
14461da177e4SLinus Torvalds 
14471da177e4SLinus Torvalds 	tunnel->dev = dev;
14485e6700b3SNicolas Dichtel 	tunnel->net = dev_net(dev);
1449ebe084aaSSteffen Klassert 	strcpy(tunnel->parms.name, dev->name);
14501da177e4SLinus Torvalds 
14518a4a50f9SMichal Schmidt 	ipip6_tunnel_bind_dev(dev);
14521c213bd2SWANG Cong 	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
145315fc1f70SEric Dumazet 	if (!dev->tstats)
145415fc1f70SEric Dumazet 		return -ENOMEM;
145515fc1f70SEric Dumazet 
1456e09acddfSPaolo Abeni 	err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
1457e09acddfSPaolo Abeni 	if (err) {
1458cf71d2bcSNicolas Dichtel 		free_percpu(dev->tstats);
1459d7426c69SWANG Cong 		dev->tstats = NULL;
1460e09acddfSPaolo Abeni 		return err;
1461cf71d2bcSNicolas Dichtel 	}
1462d62607c3SJakub Kicinski 	netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL);
1463*a7b862abSEric Dumazet 	netdev_lockdep_set_classes(dev);
146415fc1f70SEric Dumazet 	return 0;
14651da177e4SLinus Torvalds }
14661da177e4SLinus Torvalds 
ipip6_fb_tunnel_init(struct net_device * dev)14674ece9009SEric Dumazet static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
14681da177e4SLinus Torvalds {
14692941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
14701da177e4SLinus Torvalds 	struct iphdr *iph = &tunnel->parms.iph;
147129182176SPavel Emelyanov 	struct net *net = dev_net(dev);
147229182176SPavel Emelyanov 	struct sit_net *sitn = net_generic(net, sit_net_id);
14731da177e4SLinus Torvalds 
14741da177e4SLinus Torvalds 	iph->version		= 4;
14751da177e4SLinus Torvalds 	iph->protocol		= IPPROTO_IPV6;
14761da177e4SLinus Torvalds 	iph->ihl		= 5;
14771da177e4SLinus Torvalds 	iph->ttl		= 64;
14781da177e4SLinus Torvalds 
1479cf778b00SEric Dumazet 	rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
14801da177e4SLinus Torvalds }
14811da177e4SLinus Torvalds 
ipip6_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1482a8b8a889SMatthias Schiffer static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[],
1483a8b8a889SMatthias Schiffer 			  struct netlink_ext_ack *extack)
148432b8a8e5SNicolas Dichtel {
148532b8a8e5SNicolas Dichtel 	u8 proto;
148632b8a8e5SNicolas Dichtel 
1487c2ff682aSNicolas Dichtel 	if (!data || !data[IFLA_IPTUN_PROTO])
148832b8a8e5SNicolas Dichtel 		return 0;
148932b8a8e5SNicolas Dichtel 
149032b8a8e5SNicolas Dichtel 	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
149149dbe7aeSSimon Horman 	if (!ipip6_valid_ip_proto(proto))
149232b8a8e5SNicolas Dichtel 		return -EINVAL;
149332b8a8e5SNicolas Dichtel 
149432b8a8e5SNicolas Dichtel 	return 0;
149532b8a8e5SNicolas Dichtel }
149632b8a8e5SNicolas Dichtel 
ipip6_netlink_parms(struct nlattr * data[],struct ip_tunnel_parm * parms,__u32 * fwmark)1497f3723416SNicolas Dichtel static void ipip6_netlink_parms(struct nlattr *data[],
14989830ad4cSCraig Gallek 				struct ip_tunnel_parm *parms,
14999830ad4cSCraig Gallek 				__u32 *fwmark)
1500f3723416SNicolas Dichtel {
1501f3723416SNicolas Dichtel 	memset(parms, 0, sizeof(*parms));
1502f3723416SNicolas Dichtel 
1503f3723416SNicolas Dichtel 	parms->iph.version = 4;
1504f3723416SNicolas Dichtel 	parms->iph.protocol = IPPROTO_IPV6;
1505f3723416SNicolas Dichtel 	parms->iph.ihl = 5;
1506f3723416SNicolas Dichtel 	parms->iph.ttl = 64;
1507f3723416SNicolas Dichtel 
1508f3723416SNicolas Dichtel 	if (!data)
1509f3723416SNicolas Dichtel 		return;
1510f3723416SNicolas Dichtel 
1511b86fca80SLiu Jian 	ip_tunnel_netlink_parms(data, parms);
151232b8a8e5SNicolas Dichtel 
15139830ad4cSCraig Gallek 	if (data[IFLA_IPTUN_FWMARK])
15149830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
1515f3723416SNicolas Dichtel }
1516f3723416SNicolas Dichtel 
1517e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1518e2f1f072SNicolas Dichtel /* This function returns true when 6RD attributes are present in the nl msg */
ipip6_netlink_6rd_parms(struct nlattr * data[],struct ip_tunnel_6rd * ip6rd)1519e2f1f072SNicolas Dichtel static bool ipip6_netlink_6rd_parms(struct nlattr *data[],
1520e2f1f072SNicolas Dichtel 				    struct ip_tunnel_6rd *ip6rd)
1521e2f1f072SNicolas Dichtel {
1522e2f1f072SNicolas Dichtel 	bool ret = false;
1523e2f1f072SNicolas Dichtel 	memset(ip6rd, 0, sizeof(*ip6rd));
1524e2f1f072SNicolas Dichtel 
1525e2f1f072SNicolas Dichtel 	if (!data)
1526e2f1f072SNicolas Dichtel 		return ret;
1527e2f1f072SNicolas Dichtel 
1528e2f1f072SNicolas Dichtel 	if (data[IFLA_IPTUN_6RD_PREFIX]) {
1529e2f1f072SNicolas Dichtel 		ret = true;
153067b61f6cSJiri Benc 		ip6rd->prefix = nla_get_in6_addr(data[IFLA_IPTUN_6RD_PREFIX]);
1531e2f1f072SNicolas Dichtel 	}
1532e2f1f072SNicolas Dichtel 
1533e2f1f072SNicolas Dichtel 	if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) {
1534e2f1f072SNicolas Dichtel 		ret = true;
1535e2f1f072SNicolas Dichtel 		ip6rd->relay_prefix =
1536e2f1f072SNicolas Dichtel 			nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]);
1537e2f1f072SNicolas Dichtel 	}
1538e2f1f072SNicolas Dichtel 
1539e2f1f072SNicolas Dichtel 	if (data[IFLA_IPTUN_6RD_PREFIXLEN]) {
1540e2f1f072SNicolas Dichtel 		ret = true;
1541e2f1f072SNicolas Dichtel 		ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]);
1542e2f1f072SNicolas Dichtel 	}
1543e2f1f072SNicolas Dichtel 
1544e2f1f072SNicolas Dichtel 	if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) {
1545e2f1f072SNicolas Dichtel 		ret = true;
1546e2f1f072SNicolas Dichtel 		ip6rd->relay_prefixlen =
1547e2f1f072SNicolas Dichtel 			nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
1548e2f1f072SNicolas Dichtel 	}
1549e2f1f072SNicolas Dichtel 
1550e2f1f072SNicolas Dichtel 	return ret;
1551e2f1f072SNicolas Dichtel }
1552e2f1f072SNicolas Dichtel #endif
1553e2f1f072SNicolas Dichtel 
ipip6_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1554f3723416SNicolas Dichtel static int ipip6_newlink(struct net *src_net, struct net_device *dev,
15557a3f4a18SMatthias Schiffer 			 struct nlattr *tb[], struct nlattr *data[],
15567a3f4a18SMatthias Schiffer 			 struct netlink_ext_ack *extack)
1557f3723416SNicolas Dichtel {
1558f3723416SNicolas Dichtel 	struct net *net = dev_net(dev);
1559f3723416SNicolas Dichtel 	struct ip_tunnel *nt;
156014909664STom Herbert 	struct ip_tunnel_encap ipencap;
1561e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1562e2f1f072SNicolas Dichtel 	struct ip_tunnel_6rd ip6rd;
1563e2f1f072SNicolas Dichtel #endif
1564e2f1f072SNicolas Dichtel 	int err;
1565f3723416SNicolas Dichtel 
1566f3723416SNicolas Dichtel 	nt = netdev_priv(dev);
156714909664STom Herbert 
1568537dd2d9SLiu Jian 	if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
156914909664STom Herbert 		err = ip_tunnel_encap_setup(nt, &ipencap);
157014909664STom Herbert 		if (err < 0)
157114909664STom Herbert 			return err;
157214909664STom Herbert 	}
157314909664STom Herbert 
15749830ad4cSCraig Gallek 	ipip6_netlink_parms(data, &nt->parms, &nt->fwmark);
1575f3723416SNicolas Dichtel 
1576f3723416SNicolas Dichtel 	if (ipip6_tunnel_locate(net, &nt->parms, 0))
1577f3723416SNicolas Dichtel 		return -EEXIST;
1578f3723416SNicolas Dichtel 
1579e2f1f072SNicolas Dichtel 	err = ipip6_tunnel_create(dev);
1580e2f1f072SNicolas Dichtel 	if (err < 0)
1581e2f1f072SNicolas Dichtel 		return err;
1582e2f1f072SNicolas Dichtel 
15832b3957c3SXin Long 	if (tb[IFLA_MTU]) {
15842b3957c3SXin Long 		u32 mtu = nla_get_u32(tb[IFLA_MTU]);
15852b3957c3SXin Long 
1586f7ff1fdeSNicolas Dichtel 		if (mtu >= IPV6_MIN_MTU &&
1587f7ff1fdeSNicolas Dichtel 		    mtu <= IP6_MAX_MTU - dev->hard_header_len)
15882b3957c3SXin Long 			dev->mtu = mtu;
15892b3957c3SXin Long 	}
15902b3957c3SXin Long 
1591e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
159247e4bb14SJakub Kicinski 	if (ipip6_netlink_6rd_parms(data, &ip6rd)) {
1593e2f1f072SNicolas Dichtel 		err = ipip6_tunnel_update_6rd(nt, &ip6rd);
159447e4bb14SJakub Kicinski 		if (err < 0)
159547e4bb14SJakub Kicinski 			unregister_netdevice_queue(dev, NULL);
159647e4bb14SJakub Kicinski 	}
1597e2f1f072SNicolas Dichtel #endif
1598e2f1f072SNicolas Dichtel 
1599e2f1f072SNicolas Dichtel 	return err;
1600f3723416SNicolas Dichtel }
1601f3723416SNicolas Dichtel 
ipip6_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1602f3723416SNicolas Dichtel static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
1603ad744b22SMatthias Schiffer 			    struct nlattr *data[],
1604ad744b22SMatthias Schiffer 			    struct netlink_ext_ack *extack)
1605f3723416SNicolas Dichtel {
160686bd68bfSNicolas Dichtel 	struct ip_tunnel *t = netdev_priv(dev);
1607f3723416SNicolas Dichtel 	struct ip_tunnel_parm p;
160814909664STom Herbert 	struct ip_tunnel_encap ipencap;
160986bd68bfSNicolas Dichtel 	struct net *net = t->net;
1610f3723416SNicolas Dichtel 	struct sit_net *sitn = net_generic(net, sit_net_id);
1611e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1612e2f1f072SNicolas Dichtel 	struct ip_tunnel_6rd ip6rd;
1613e2f1f072SNicolas Dichtel #endif
16149830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
161514909664STom Herbert 	int err;
1616f3723416SNicolas Dichtel 
1617f3723416SNicolas Dichtel 	if (dev == sitn->fb_tunnel_dev)
1618f3723416SNicolas Dichtel 		return -EINVAL;
1619f3723416SNicolas Dichtel 
1620537dd2d9SLiu Jian 	if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
162114909664STom Herbert 		err = ip_tunnel_encap_setup(t, &ipencap);
162214909664STom Herbert 		if (err < 0)
162314909664STom Herbert 			return err;
162414909664STom Herbert 	}
162514909664STom Herbert 
16269830ad4cSCraig Gallek 	ipip6_netlink_parms(data, &p, &fwmark);
1627f3723416SNicolas Dichtel 
1628f3723416SNicolas Dichtel 	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
1629f3723416SNicolas Dichtel 	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
1630f3723416SNicolas Dichtel 		return -EINVAL;
1631f3723416SNicolas Dichtel 
1632f3723416SNicolas Dichtel 	t = ipip6_tunnel_locate(net, &p, 0);
1633f3723416SNicolas Dichtel 
1634f3723416SNicolas Dichtel 	if (t) {
1635f3723416SNicolas Dichtel 		if (t->dev != dev)
1636f3723416SNicolas Dichtel 			return -EEXIST;
1637f3723416SNicolas Dichtel 	} else
1638f3723416SNicolas Dichtel 		t = netdev_priv(dev);
1639f3723416SNicolas Dichtel 
16409830ad4cSCraig Gallek 	ipip6_tunnel_update(t, &p, fwmark);
1641e2f1f072SNicolas Dichtel 
1642e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1643e2f1f072SNicolas Dichtel 	if (ipip6_netlink_6rd_parms(data, &ip6rd))
1644e2f1f072SNicolas Dichtel 		return ipip6_tunnel_update_6rd(t, &ip6rd);
1645e2f1f072SNicolas Dichtel #endif
1646e2f1f072SNicolas Dichtel 
1647f3723416SNicolas Dichtel 	return 0;
1648f3723416SNicolas Dichtel }
1649f3723416SNicolas Dichtel 
ipip6_get_size(const struct net_device * dev)1650e4c94a9cSNicolas Dichtel static size_t ipip6_get_size(const struct net_device *dev)
1651ba3e3f50SNicolas Dichtel {
1652ba3e3f50SNicolas Dichtel 	return
1653ba3e3f50SNicolas Dichtel 		/* IFLA_IPTUN_LINK */
1654ba3e3f50SNicolas Dichtel 		nla_total_size(4) +
1655ba3e3f50SNicolas Dichtel 		/* IFLA_IPTUN_LOCAL */
1656ba3e3f50SNicolas Dichtel 		nla_total_size(4) +
1657ba3e3f50SNicolas Dichtel 		/* IFLA_IPTUN_REMOTE */
1658ba3e3f50SNicolas Dichtel 		nla_total_size(4) +
1659ba3e3f50SNicolas Dichtel 		/* IFLA_IPTUN_TTL */
1660ba3e3f50SNicolas Dichtel 		nla_total_size(1) +
1661ba3e3f50SNicolas Dichtel 		/* IFLA_IPTUN_TOS */
1662ba3e3f50SNicolas Dichtel 		nla_total_size(1) +
1663a12c9a85SNicolas Dichtel 		/* IFLA_IPTUN_PMTUDISC */
1664a12c9a85SNicolas Dichtel 		nla_total_size(1) +
1665a12c9a85SNicolas Dichtel 		/* IFLA_IPTUN_FLAGS */
1666a12c9a85SNicolas Dichtel 		nla_total_size(2) +
166732b8a8e5SNicolas Dichtel 		/* IFLA_IPTUN_PROTO */
166832b8a8e5SNicolas Dichtel 		nla_total_size(1) +
1669e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1670e2f1f072SNicolas Dichtel 		/* IFLA_IPTUN_6RD_PREFIX */
1671e2f1f072SNicolas Dichtel 		nla_total_size(sizeof(struct in6_addr)) +
1672e2f1f072SNicolas Dichtel 		/* IFLA_IPTUN_6RD_RELAY_PREFIX */
1673e2f1f072SNicolas Dichtel 		nla_total_size(4) +
1674e2f1f072SNicolas Dichtel 		/* IFLA_IPTUN_6RD_PREFIXLEN */
1675e2f1f072SNicolas Dichtel 		nla_total_size(2) +
1676e2f1f072SNicolas Dichtel 		/* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */
1677e2f1f072SNicolas Dichtel 		nla_total_size(2) +
1678e2f1f072SNicolas Dichtel #endif
167914909664STom Herbert 		/* IFLA_IPTUN_ENCAP_TYPE */
168014909664STom Herbert 		nla_total_size(2) +
168114909664STom Herbert 		/* IFLA_IPTUN_ENCAP_FLAGS */
168214909664STom Herbert 		nla_total_size(2) +
168314909664STom Herbert 		/* IFLA_IPTUN_ENCAP_SPORT */
168414909664STom Herbert 		nla_total_size(2) +
168514909664STom Herbert 		/* IFLA_IPTUN_ENCAP_DPORT */
168614909664STom Herbert 		nla_total_size(2) +
16879830ad4cSCraig Gallek 		/* IFLA_IPTUN_FWMARK */
16889830ad4cSCraig Gallek 		nla_total_size(4) +
1689ba3e3f50SNicolas Dichtel 		0;
1690ba3e3f50SNicolas Dichtel }
1691ba3e3f50SNicolas Dichtel 
ipip6_fill_info(struct sk_buff * skb,const struct net_device * dev)1692e4c94a9cSNicolas Dichtel static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
1693ba3e3f50SNicolas Dichtel {
1694ba3e3f50SNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
1695ba3e3f50SNicolas Dichtel 	struct ip_tunnel_parm *parm = &tunnel->parms;
1696ba3e3f50SNicolas Dichtel 
1697ba3e3f50SNicolas Dichtel 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
1698930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
1699930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
1700ba3e3f50SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
1701a12c9a85SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
1702a12c9a85SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
1703a12c9a85SNicolas Dichtel 		       !!(parm->iph.frag_off & htons(IP_DF))) ||
170432b8a8e5SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
17059830ad4cSCraig Gallek 	    nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags) ||
17069830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
1707ba3e3f50SNicolas Dichtel 		goto nla_put_failure;
1708e2f1f072SNicolas Dichtel 
1709e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1710930345eaSJiri Benc 	if (nla_put_in6_addr(skb, IFLA_IPTUN_6RD_PREFIX,
1711e2f1f072SNicolas Dichtel 			     &tunnel->ip6rd.prefix) ||
1712930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_6RD_RELAY_PREFIX,
1713e2f1f072SNicolas Dichtel 			    tunnel->ip6rd.relay_prefix) ||
1714e2f1f072SNicolas Dichtel 	    nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN,
1715e2f1f072SNicolas Dichtel 			tunnel->ip6rd.prefixlen) ||
1716e2f1f072SNicolas Dichtel 	    nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
1717e2f1f072SNicolas Dichtel 			tunnel->ip6rd.relay_prefixlen))
1718e2f1f072SNicolas Dichtel 		goto nla_put_failure;
1719e2f1f072SNicolas Dichtel #endif
1720e2f1f072SNicolas Dichtel 
172114909664STom Herbert 	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
172214909664STom Herbert 			tunnel->encap.type) ||
1723a409caecSEric Dumazet 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
172414909664STom Herbert 			tunnel->encap.sport) ||
1725a409caecSEric Dumazet 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
172614909664STom Herbert 			tunnel->encap.dport) ||
172714909664STom Herbert 	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
1728e1b2cb65STom Herbert 			tunnel->encap.flags))
172914909664STom Herbert 		goto nla_put_failure;
173014909664STom Herbert 
1731ba3e3f50SNicolas Dichtel 	return 0;
1732ba3e3f50SNicolas Dichtel 
1733ba3e3f50SNicolas Dichtel nla_put_failure:
1734ba3e3f50SNicolas Dichtel 	return -EMSGSIZE;
1735ba3e3f50SNicolas Dichtel }
1736ba3e3f50SNicolas Dichtel 
1737f3723416SNicolas Dichtel static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
1738f3723416SNicolas Dichtel 	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
1739f3723416SNicolas Dichtel 	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
1740f3723416SNicolas Dichtel 	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
1741f3723416SNicolas Dichtel 	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
1742f3723416SNicolas Dichtel 	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
1743f3723416SNicolas Dichtel 	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
1744f3723416SNicolas Dichtel 	[IFLA_IPTUN_FLAGS]		= { .type = NLA_U16 },
174532b8a8e5SNicolas Dichtel 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
1746e2f1f072SNicolas Dichtel #ifdef CONFIG_IPV6_SIT_6RD
1747e2f1f072SNicolas Dichtel 	[IFLA_IPTUN_6RD_PREFIX]		= { .len = sizeof(struct in6_addr) },
1748e2f1f072SNicolas Dichtel 	[IFLA_IPTUN_6RD_RELAY_PREFIX]	= { .type = NLA_U32 },
1749e2f1f072SNicolas Dichtel 	[IFLA_IPTUN_6RD_PREFIXLEN]	= { .type = NLA_U16 },
1750e2f1f072SNicolas Dichtel 	[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
1751e2f1f072SNicolas Dichtel #endif
175214909664STom Herbert 	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
175314909664STom Herbert 	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
175414909664STom Herbert 	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
175514909664STom Herbert 	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
17569830ad4cSCraig Gallek 	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
1757f3723416SNicolas Dichtel };
1758f3723416SNicolas Dichtel 
ipip6_dellink(struct net_device * dev,struct list_head * head)17599434266fSWillem de Bruijn static void ipip6_dellink(struct net_device *dev, struct list_head *head)
17609434266fSWillem de Bruijn {
17619434266fSWillem de Bruijn 	struct net *net = dev_net(dev);
17629434266fSWillem de Bruijn 	struct sit_net *sitn = net_generic(net, sit_net_id);
17639434266fSWillem de Bruijn 
17649434266fSWillem de Bruijn 	if (dev != sitn->fb_tunnel_dev)
17659434266fSWillem de Bruijn 		unregister_netdevice_queue(dev, head);
17669434266fSWillem de Bruijn }
17679434266fSWillem de Bruijn 
1768ba3e3f50SNicolas Dichtel static struct rtnl_link_ops sit_link_ops __read_mostly = {
1769ba3e3f50SNicolas Dichtel 	.kind		= "sit",
1770ba3e3f50SNicolas Dichtel 	.maxtype	= IFLA_IPTUN_MAX,
1771f3723416SNicolas Dichtel 	.policy		= ipip6_policy,
1772ba3e3f50SNicolas Dichtel 	.priv_size	= sizeof(struct ip_tunnel),
1773f3723416SNicolas Dichtel 	.setup		= ipip6_tunnel_setup,
177432b8a8e5SNicolas Dichtel 	.validate	= ipip6_validate,
1775f3723416SNicolas Dichtel 	.newlink	= ipip6_newlink,
1776f3723416SNicolas Dichtel 	.changelink	= ipip6_changelink,
1777e4c94a9cSNicolas Dichtel 	.get_size	= ipip6_get_size,
1778e4c94a9cSNicolas Dichtel 	.fill_info	= ipip6_fill_info,
17799434266fSWillem de Bruijn 	.dellink	= ipip6_dellink,
17801728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
1781ba3e3f50SNicolas Dichtel };
1782ba3e3f50SNicolas Dichtel 
17836dcd814bSEric Dumazet static struct xfrm_tunnel sit_handler __read_mostly = {
17841da177e4SLinus Torvalds 	.handler	=	ipip6_rcv,
17851da177e4SLinus Torvalds 	.err_handler	=	ipip6_err,
1786c73cb5a2SKazunori MIYAZAWA 	.priority	=	1,
17871da177e4SLinus Torvalds };
17881da177e4SLinus Torvalds 
178932b8a8e5SNicolas Dichtel static struct xfrm_tunnel ipip_handler __read_mostly = {
179032b8a8e5SNicolas Dichtel 	.handler	=	ipip_rcv,
179132b8a8e5SNicolas Dichtel 	.err_handler	=	ipip6_err,
179232b8a8e5SNicolas Dichtel 	.priority	=	2,
179332b8a8e5SNicolas Dichtel };
179432b8a8e5SNicolas Dichtel 
179549dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
179649dbe7aeSSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = {
179749dbe7aeSSimon Horman 	.handler	=	mplsip_rcv,
179849dbe7aeSSimon Horman 	.err_handler	=	ipip6_err,
179949dbe7aeSSimon Horman 	.priority	=	2,
180049dbe7aeSSimon Horman };
180149dbe7aeSSimon Horman #endif
180249dbe7aeSSimon Horman 
sit_destroy_tunnels(struct net * net,struct list_head * head)18039434266fSWillem de Bruijn static void __net_exit sit_destroy_tunnels(struct net *net,
18049434266fSWillem de Bruijn 					   struct list_head *head)
1805db44575fSAlexey Kuznetsov {
18069434266fSWillem de Bruijn 	struct sit_net *sitn = net_generic(net, sit_net_id);
18075e6700b3SNicolas Dichtel 	struct net_device *dev, *aux;
1808db44575fSAlexey Kuznetsov 	int prio;
1809db44575fSAlexey Kuznetsov 
18105e6700b3SNicolas Dichtel 	for_each_netdev_safe(net, dev, aux)
18115e6700b3SNicolas Dichtel 		if (dev->rtnl_link_ops == &sit_link_ops)
18125e6700b3SNicolas Dichtel 			unregister_netdevice_queue(dev, head);
18135e6700b3SNicolas Dichtel 
1814610f8c0fSHristo Venev 	for (prio = 0; prio < 4; prio++) {
1815db44575fSAlexey Kuznetsov 		int h;
1816610f8c0fSHristo Venev 		for (h = 0; h < (prio ? IP6_SIT_HASH_SIZE : 1); h++) {
1817753ea8e9SEric Dumazet 			struct ip_tunnel *t;
181862808f91SEric Dumazet 
1819753ea8e9SEric Dumazet 			t = rtnl_dereference(sitn->tunnels[prio][h]);
182053b24b8fSIan Morris 			while (t) {
18215e6700b3SNicolas Dichtel 				/* If dev is in the same netns, it has already
18225e6700b3SNicolas Dichtel 				 * been added to the list by the previous loop.
18235e6700b3SNicolas Dichtel 				 */
1824fc8f999dSNicolas Dichtel 				if (!net_eq(dev_net(t->dev), net))
18255e6700b3SNicolas Dichtel 					unregister_netdevice_queue(t->dev,
18265e6700b3SNicolas Dichtel 								   head);
1827753ea8e9SEric Dumazet 				t = rtnl_dereference(t->next);
182862808f91SEric Dumazet 			}
1829db44575fSAlexey Kuznetsov 		}
1830db44575fSAlexey Kuznetsov 	}
1831db44575fSAlexey Kuznetsov }
1832db44575fSAlexey Kuznetsov 
sit_init_net(struct net * net)18332c8c1e72SAlexey Dobriyan static int __net_init sit_init_net(struct net *net)
18348190d900SPavel Emelyanov {
183567101172SEric W. Biederman 	struct sit_net *sitn = net_generic(net, sit_net_id);
183672b36015STed Feng 	struct ip_tunnel *t;
18378190d900SPavel Emelyanov 	int err;
18388190d900SPavel Emelyanov 
183929182176SPavel Emelyanov 	sitn->tunnels[0] = sitn->tunnels_wc;
184029182176SPavel Emelyanov 	sitn->tunnels[1] = sitn->tunnels_l;
184129182176SPavel Emelyanov 	sitn->tunnels[2] = sitn->tunnels_r;
184229182176SPavel Emelyanov 	sitn->tunnels[3] = sitn->tunnels_r_l;
184329182176SPavel Emelyanov 
184479134e6cSEric Dumazet 	if (!net_has_fallback_tunnels(net))
184579134e6cSEric Dumazet 		return 0;
184679134e6cSEric Dumazet 
1847cd3dbc19SPavel Emelyanov 	sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0",
1848c835a677STom Gundersen 					   NET_NAME_UNKNOWN,
1849cd3dbc19SPavel Emelyanov 					   ipip6_tunnel_setup);
1850cd3dbc19SPavel Emelyanov 	if (!sitn->fb_tunnel_dev) {
1851cd3dbc19SPavel Emelyanov 		err = -ENOMEM;
1852cd3dbc19SPavel Emelyanov 		goto err_alloc_dev;
1853cd3dbc19SPavel Emelyanov 	}
1854be77e593SAlexey Dobriyan 	dev_net_set(sitn->fb_tunnel_dev, net);
1855205983c4SNicolas Dichtel 	sitn->fb_tunnel_dev->rtnl_link_ops = &sit_link_ops;
18565e6700b3SNicolas Dichtel 	/* FB netdevice is special: we have one, and only one per netns.
18575e6700b3SNicolas Dichtel 	 * Allowing to move it to another netns is clearly unsafe.
18585e6700b3SNicolas Dichtel 	 */
18595e6700b3SNicolas Dichtel 	sitn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
1860cd3dbc19SPavel Emelyanov 
1861e5d08d71SIan Morris 	err = register_netdev(sitn->fb_tunnel_dev);
1862e5d08d71SIan Morris 	if (err)
1863cd3dbc19SPavel Emelyanov 		goto err_reg_dev;
1864cd3dbc19SPavel Emelyanov 
18654ece9009SEric Dumazet 	ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
18664ece9009SEric Dumazet 	ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
18674ece9009SEric Dumazet 
186872b36015STed Feng 	t = netdev_priv(sitn->fb_tunnel_dev);
186972b36015STed Feng 
187072b36015STed Feng 	strcpy(t->parms.name, sitn->fb_tunnel_dev->name);
18718190d900SPavel Emelyanov 	return 0;
18728190d900SPavel Emelyanov 
1873cd3dbc19SPavel Emelyanov err_reg_dev:
187407f12b26SMao Wenan 	free_netdev(sitn->fb_tunnel_dev);
1875cd3dbc19SPavel Emelyanov err_alloc_dev:
18768190d900SPavel Emelyanov 	return err;
18778190d900SPavel Emelyanov }
18788190d900SPavel Emelyanov 
sit_exit_batch_net(struct list_head * net_list)1879bb401caeSEric Dumazet static void __net_exit sit_exit_batch_net(struct list_head *net_list)
18808190d900SPavel Emelyanov {
188162808f91SEric Dumazet 	LIST_HEAD(list);
1882bb401caeSEric Dumazet 	struct net *net;
18838190d900SPavel Emelyanov 
1884cd3dbc19SPavel Emelyanov 	rtnl_lock();
1885bb401caeSEric Dumazet 	list_for_each_entry(net, net_list, exit_list)
18869434266fSWillem de Bruijn 		sit_destroy_tunnels(net, &list);
1887bb401caeSEric Dumazet 
188862808f91SEric Dumazet 	unregister_netdevice_many(&list);
1889cd3dbc19SPavel Emelyanov 	rtnl_unlock();
18908190d900SPavel Emelyanov }
18918190d900SPavel Emelyanov 
18928190d900SPavel Emelyanov static struct pernet_operations sit_net_ops = {
18938190d900SPavel Emelyanov 	.init = sit_init_net,
1894bb401caeSEric Dumazet 	.exit_batch = sit_exit_batch_net,
189567101172SEric W. Biederman 	.id   = &sit_net_id,
189667101172SEric W. Biederman 	.size = sizeof(struct sit_net),
18978190d900SPavel Emelyanov };
18988190d900SPavel Emelyanov 
sit_cleanup(void)189989c89458SAdrian Bunk static void __exit sit_cleanup(void)
19001da177e4SLinus Torvalds {
1901ba3e3f50SNicolas Dichtel 	rtnl_link_unregister(&sit_link_ops);
1902c73cb5a2SKazunori MIYAZAWA 	xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
190332b8a8e5SNicolas Dichtel 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
190449dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
190549dbe7aeSSimon Horman 	xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
190649dbe7aeSSimon Horman #endif
1907db44575fSAlexey Kuznetsov 
190867101172SEric W. Biederman 	unregister_pernet_device(&sit_net_ops);
1909ef9a9d11SEric Dumazet 	rcu_barrier(); /* Wait for completion of call_rcu()'s */
19101da177e4SLinus Torvalds }
19111da177e4SLinus Torvalds 
sit_init(void)191289c89458SAdrian Bunk static int __init sit_init(void)
19131da177e4SLinus Torvalds {
19141da177e4SLinus Torvalds 	int err;
19151da177e4SLinus Torvalds 
191649dbe7aeSSimon Horman 	pr_info("IPv6, IPv4 and MPLS over IPv4 tunneling driver\n");
19171da177e4SLinus Torvalds 
191867101172SEric W. Biederman 	err = register_pernet_device(&sit_net_ops);
19198190d900SPavel Emelyanov 	if (err < 0)
1920d5aa407fSAlexey Dobriyan 		return err;
1921d5aa407fSAlexey Dobriyan 	err = xfrm4_tunnel_register(&sit_handler, AF_INET6);
1922d5aa407fSAlexey Dobriyan 	if (err < 0) {
192332b8a8e5SNicolas Dichtel 		pr_info("%s: can't register ip6ip4\n", __func__);
1924ba3e3f50SNicolas Dichtel 		goto xfrm_tunnel_failed;
1925d5aa407fSAlexey Dobriyan 	}
192632b8a8e5SNicolas Dichtel 	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
192732b8a8e5SNicolas Dichtel 	if (err < 0) {
192832b8a8e5SNicolas Dichtel 		pr_info("%s: can't register ip4ip4\n", __func__);
192932b8a8e5SNicolas Dichtel 		goto xfrm_tunnel4_failed;
193032b8a8e5SNicolas Dichtel 	}
193149dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
193249dbe7aeSSimon Horman 	err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
193349dbe7aeSSimon Horman 	if (err < 0) {
193449dbe7aeSSimon Horman 		pr_info("%s: can't register mplsip\n", __func__);
193549dbe7aeSSimon Horman 		goto xfrm_tunnel_mpls_failed;
193649dbe7aeSSimon Horman 	}
193749dbe7aeSSimon Horman #endif
1938ba3e3f50SNicolas Dichtel 	err = rtnl_link_register(&sit_link_ops);
1939ba3e3f50SNicolas Dichtel 	if (err < 0)
1940ba3e3f50SNicolas Dichtel 		goto rtnl_link_failed;
1941ba3e3f50SNicolas Dichtel 
1942ba3e3f50SNicolas Dichtel out:
1943cd3dbc19SPavel Emelyanov 	return err;
1944ba3e3f50SNicolas Dichtel 
1945ba3e3f50SNicolas Dichtel rtnl_link_failed:
194649dbe7aeSSimon Horman #if IS_ENABLED(CONFIG_MPLS)
194749dbe7aeSSimon Horman 	xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
194849dbe7aeSSimon Horman xfrm_tunnel_mpls_failed:
194949dbe7aeSSimon Horman #endif
195032b8a8e5SNicolas Dichtel 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
195132b8a8e5SNicolas Dichtel xfrm_tunnel4_failed:
1952ba3e3f50SNicolas Dichtel 	xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
1953ba3e3f50SNicolas Dichtel xfrm_tunnel_failed:
1954ba3e3f50SNicolas Dichtel 	unregister_pernet_device(&sit_net_ops);
1955ba3e3f50SNicolas Dichtel 	goto out;
19561da177e4SLinus Torvalds }
1957989e5b96SJoerg Roedel 
1958989e5b96SJoerg Roedel module_init(sit_init);
1959989e5b96SJoerg Roedel module_exit(sit_cleanup);
196039c85086SJan Dittmer MODULE_LICENSE("GPL");
1961f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("sit");
19628909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("sit0");
1963