xref: /linux/net/ipv4/ipip.c (revision 4f3ed9209f7f75ff0ee21bc5052d76542dd75b5f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	Linux NET3:	IP/IP protocol decoder.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *	Authors:
51da177e4SLinus Torvalds  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *	Fixes:
81da177e4SLinus Torvalds  *		Alan Cox	:	Merged and made usable non modular (its so tiny its silly as
91da177e4SLinus Torvalds  *					a module taking up 2 pages).
101da177e4SLinus Torvalds  *		Alan Cox	: 	Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
111da177e4SLinus Torvalds  *					to keep ip_forward happy.
121da177e4SLinus Torvalds  *		Alan Cox	:	More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
131da177e4SLinus Torvalds  *		Kai Schulte	:	Fixed #defines for IP_FIREWALL->FIREWALL
141da177e4SLinus Torvalds  *              David Woodhouse :       Perform some basic ICMP handling.
151da177e4SLinus Torvalds  *                                      IPIP Routing without decapsulation.
161da177e4SLinus Torvalds  *              Carlos Picoto   :       GRE over IP support
171da177e4SLinus Torvalds  *		Alexey Kuznetsov:	Reworked. Really, now it is truncated version of ipv4/ip_gre.c.
181da177e4SLinus Torvalds  *					I do not want to merge them together.
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
211da177e4SLinus Torvalds  *	modify it under the terms of the GNU General Public License
221da177e4SLinus Torvalds  *	as published by the Free Software Foundation; either version
231da177e4SLinus Torvalds  *	2 of the License, or (at your option) any later version.
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /* tunnel.c: an IP tunnel driver
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 	The purpose of this driver is to provide an IP tunnel through
301da177e4SLinus Torvalds 	which you can tunnel network traffic transparently across subnets.
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 	This was written by looking at Nick Holloway's dummy driver
331da177e4SLinus Torvalds 	Thanks for the great code!
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 		-Sam Lantinga	(slouken@cs.ucdavis.edu)  02/01/95
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	Minor tweaks:
381da177e4SLinus Torvalds 		Cleaned up the code a little and added some pre-1.3.0 tweaks.
391da177e4SLinus Torvalds 		dev->hard_header/hard_header_len changed to use no headers.
401da177e4SLinus Torvalds 		Comments/bracketing tweaked.
411da177e4SLinus Torvalds 		Made the tunnels use dev->name not tunnel: when error reporting.
421da177e4SLinus Torvalds 		Added tx_dropped stat
431da177e4SLinus Torvalds 
44113aa838SAlan Cox 		-Alan Cox	(alan@lxorguk.ukuu.org.uk) 21 March 95
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 	Reworked:
471da177e4SLinus Torvalds 		Changed to tunnel to destination gateway in addition to the
481da177e4SLinus Torvalds 			tunnel's pointopoint address
491da177e4SLinus Torvalds 		Almost completely rewritten
501da177e4SLinus Torvalds 		Note:  There is currently no firewall or ICMP handling done.
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 		-Sam Lantinga	(slouken@cs.ucdavis.edu) 02/13/96
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds */
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds /* Things I wish I had known when writing the tunnel driver:
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	When the tunnel_xmit() function is called, the skb contains the
591da177e4SLinus Torvalds 	packet to be sent (plus a great deal of extra info), and dev
601da177e4SLinus Torvalds 	contains the tunnel device that _we_ are.
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	When we are passed a packet, we are expected to fill in the
631da177e4SLinus Torvalds 	source address with our source IP address.
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	What is the proper way to allocate, copy and free a buffer?
661da177e4SLinus Torvalds 	After you allocate it, it is a "0 length" chunk of memory
671da177e4SLinus Torvalds 	starting at zero.  If you want to add headers to the buffer
681da177e4SLinus Torvalds 	later, you'll have to call "skb_reserve(skb, amount)" with
691da177e4SLinus Torvalds 	the amount of memory you want reserved.  Then, you call
701da177e4SLinus Torvalds 	"skb_put(skb, amount)" with the amount of space you want in
711da177e4SLinus Torvalds 	the buffer.  skb_put() returns a pointer to the top (#0) of
721da177e4SLinus Torvalds 	that buffer.  skb->len is set to the amount of space you have
731da177e4SLinus Torvalds 	"allocated" with skb_put().  You can then write up to skb->len
741da177e4SLinus Torvalds 	bytes to that buffer.  If you need more, you can call skb_put()
751da177e4SLinus Torvalds 	again with the additional amount of space you need.  You can
761da177e4SLinus Torvalds 	find out how much more space you can allocate by calling
771da177e4SLinus Torvalds 	"skb_tailroom(skb)".
781da177e4SLinus Torvalds 	Now, to add header space, call "skb_push(skb, header_len)".
791da177e4SLinus Torvalds 	This creates space at the beginning of the buffer and returns
801da177e4SLinus Torvalds 	a pointer to this new space.  If later you need to strip a
811da177e4SLinus Torvalds 	header from a buffer, call "skb_pull(skb, header_len)".
821da177e4SLinus Torvalds 	skb_headroom() will return how much space is left at the top
831da177e4SLinus Torvalds 	of the buffer (before the main data).  Remember, this headroom
841da177e4SLinus Torvalds 	space must be reserved before the skb_put() function is called.
851da177e4SLinus Torvalds 	*/
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds /*
881da177e4SLinus Torvalds    This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds    For comments look at net/ipv4/ip_gre.c --ANK
911da177e4SLinus Torvalds  */
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 
944fc268d2SRandy Dunlap #include <linux/capability.h>
951da177e4SLinus Torvalds #include <linux/module.h>
961da177e4SLinus Torvalds #include <linux/types.h>
971da177e4SLinus Torvalds #include <linux/kernel.h>
985a0e3ad6STejun Heo #include <linux/slab.h>
991da177e4SLinus Torvalds #include <asm/uaccess.h>
1001da177e4SLinus Torvalds #include <linux/skbuff.h>
1011da177e4SLinus Torvalds #include <linux/netdevice.h>
1021da177e4SLinus Torvalds #include <linux/in.h>
1031da177e4SLinus Torvalds #include <linux/tcp.h>
1041da177e4SLinus Torvalds #include <linux/udp.h>
1051da177e4SLinus Torvalds #include <linux/if_arp.h>
1061da177e4SLinus Torvalds #include <linux/mroute.h>
1071da177e4SLinus Torvalds #include <linux/init.h>
1081da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
10946f25dffSKris Katterjohn #include <linux/if_ether.h>
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds #include <net/sock.h>
1121da177e4SLinus Torvalds #include <net/ip.h>
1131da177e4SLinus Torvalds #include <net/icmp.h>
1141da177e4SLinus Torvalds #include <net/ipip.h>
1151da177e4SLinus Torvalds #include <net/inet_ecn.h>
1161da177e4SLinus Torvalds #include <net/xfrm.h>
11710dc4c7bSPavel Emelyanov #include <net/net_namespace.h>
11810dc4c7bSPavel Emelyanov #include <net/netns/generic.h>
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds #define HASH_SIZE  16
121d5a0a1e3SAl Viro #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
1221da177e4SLinus Torvalds 
123eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
124eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
125eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
126eccc1bb8Sstephen hemminger 
127f99189b1SEric Dumazet static int ipip_net_id __read_mostly;
12810dc4c7bSPavel Emelyanov struct ipip_net {
129b7285b79SEric Dumazet 	struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
130b7285b79SEric Dumazet 	struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
131b7285b79SEric Dumazet 	struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
132b7285b79SEric Dumazet 	struct ip_tunnel __rcu *tunnels_wc[1];
133b7285b79SEric Dumazet 	struct ip_tunnel __rcu **tunnels[4];
13444d3c299SPavel Emelyanov 
135b9855c54SPavel Emelyanov 	struct net_device *fb_tunnel_dev;
13610dc4c7bSPavel Emelyanov };
13710dc4c7bSPavel Emelyanov 
1383c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev);
1391da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev);
1403c97af99SEric Dumazet static void ipip_dev_free(struct net_device *dev);
1410974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly;
1421da177e4SLinus Torvalds 
14387b6d218Sstephen hemminger static struct rtnl_link_stats64 *ipip_get_stats64(struct net_device *dev,
14487b6d218Sstephen hemminger 						  struct rtnl_link_stats64 *tot)
1453c97af99SEric Dumazet {
1463c97af99SEric Dumazet 	int i;
1473c97af99SEric Dumazet 
1483c97af99SEric Dumazet 	for_each_possible_cpu(i) {
1493c97af99SEric Dumazet 		const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
15087b6d218Sstephen hemminger 		u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
15187b6d218Sstephen hemminger 		unsigned int start;
1523c97af99SEric Dumazet 
15387b6d218Sstephen hemminger 		do {
15487b6d218Sstephen hemminger 			start = u64_stats_fetch_begin_bh(&tstats->syncp);
15587b6d218Sstephen hemminger 			rx_packets = tstats->rx_packets;
15687b6d218Sstephen hemminger 			tx_packets = tstats->tx_packets;
15787b6d218Sstephen hemminger 			rx_bytes = tstats->rx_bytes;
15887b6d218Sstephen hemminger 			tx_bytes = tstats->tx_bytes;
15987b6d218Sstephen hemminger 		} while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
16087b6d218Sstephen hemminger 
16187b6d218Sstephen hemminger 		tot->rx_packets += rx_packets;
16287b6d218Sstephen hemminger 		tot->tx_packets += tx_packets;
16387b6d218Sstephen hemminger 		tot->rx_bytes   += rx_bytes;
16487b6d218Sstephen hemminger 		tot->tx_bytes   += tx_bytes;
1653c97af99SEric Dumazet 	}
16687b6d218Sstephen hemminger 
16787b6d218Sstephen hemminger 	tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
16887b6d218Sstephen hemminger 	tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
16987b6d218Sstephen hemminger 	tot->tx_dropped = dev->stats.tx_dropped;
17087b6d218Sstephen hemminger 	tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
17187b6d218Sstephen hemminger 	tot->tx_errors = dev->stats.tx_errors;
17287b6d218Sstephen hemminger 	tot->collisions = dev->stats.collisions;
17387b6d218Sstephen hemminger 
17487b6d218Sstephen hemminger 	return tot;
1753c97af99SEric Dumazet }
1763c97af99SEric Dumazet 
177b9fae5c9SPavel Emelyanov static struct ip_tunnel *ipip_tunnel_lookup(struct net *net,
178b9fae5c9SPavel Emelyanov 		__be32 remote, __be32 local)
1791da177e4SLinus Torvalds {
180b7285b79SEric Dumazet 	unsigned int h0 = HASH(remote);
181b7285b79SEric Dumazet 	unsigned int h1 = HASH(local);
1821da177e4SLinus Torvalds 	struct ip_tunnel *t;
18344d3c299SPavel Emelyanov 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
1841da177e4SLinus Torvalds 
185e086cadcSAmerigo Wang 	for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1])
1861da177e4SLinus Torvalds 		if (local == t->parms.iph.saddr &&
1871da177e4SLinus Torvalds 		    remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
1881da177e4SLinus Torvalds 			return t;
1898f95dd63SEric Dumazet 
190e086cadcSAmerigo Wang 	for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0])
1911da177e4SLinus Torvalds 		if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
1921da177e4SLinus Torvalds 			return t;
1938f95dd63SEric Dumazet 
194e086cadcSAmerigo Wang 	for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1])
1951da177e4SLinus Torvalds 		if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
1961da177e4SLinus Torvalds 			return t;
1978f95dd63SEric Dumazet 
1988f95dd63SEric Dumazet 	t = rcu_dereference(ipn->tunnels_wc[0]);
1998f95dd63SEric Dumazet 	if (t && (t->dev->flags&IFF_UP))
2001da177e4SLinus Torvalds 		return t;
2011da177e4SLinus Torvalds 	return NULL;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds 
204b7285b79SEric Dumazet static struct ip_tunnel __rcu **__ipip_bucket(struct ipip_net *ipn,
205b9fae5c9SPavel Emelyanov 		struct ip_tunnel_parm *parms)
2061da177e4SLinus Torvalds {
20787d1a164SYOSHIFUJI Hideaki 	__be32 remote = parms->iph.daddr;
20887d1a164SYOSHIFUJI Hideaki 	__be32 local = parms->iph.saddr;
209b7285b79SEric Dumazet 	unsigned int h = 0;
2101da177e4SLinus Torvalds 	int prio = 0;
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	if (remote) {
2131da177e4SLinus Torvalds 		prio |= 2;
2141da177e4SLinus Torvalds 		h ^= HASH(remote);
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 	if (local) {
2171da177e4SLinus Torvalds 		prio |= 1;
2181da177e4SLinus Torvalds 		h ^= HASH(local);
2191da177e4SLinus Torvalds 	}
22044d3c299SPavel Emelyanov 	return &ipn->tunnels[prio][h];
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
223b7285b79SEric Dumazet static inline struct ip_tunnel __rcu **ipip_bucket(struct ipip_net *ipn,
224b9fae5c9SPavel Emelyanov 		struct ip_tunnel *t)
22587d1a164SYOSHIFUJI Hideaki {
226b9fae5c9SPavel Emelyanov 	return __ipip_bucket(ipn, &t->parms);
22787d1a164SYOSHIFUJI Hideaki }
2281da177e4SLinus Torvalds 
229b9fae5c9SPavel Emelyanov static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
2301da177e4SLinus Torvalds {
231b7285b79SEric Dumazet 	struct ip_tunnel __rcu **tp;
232b7285b79SEric Dumazet 	struct ip_tunnel *iter;
2331da177e4SLinus Torvalds 
234b7285b79SEric Dumazet 	for (tp = ipip_bucket(ipn, t);
235b7285b79SEric Dumazet 	     (iter = rtnl_dereference(*tp)) != NULL;
236b7285b79SEric Dumazet 	     tp = &iter->next) {
237b7285b79SEric Dumazet 		if (t == iter) {
238cf778b00SEric Dumazet 			rcu_assign_pointer(*tp, t->next);
2391da177e4SLinus Torvalds 			break;
2401da177e4SLinus Torvalds 		}
2411da177e4SLinus Torvalds 	}
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds 
244b9fae5c9SPavel Emelyanov static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
2451da177e4SLinus Torvalds {
246b7285b79SEric Dumazet 	struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
2471da177e4SLinus Torvalds 
248cf778b00SEric Dumazet 	rcu_assign_pointer(t->next, rtnl_dereference(*tp));
249cf778b00SEric Dumazet 	rcu_assign_pointer(*tp, t);
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds 
252be42da0eSNicolas Dichtel static int ipip_tunnel_create(struct net_device *dev)
253be42da0eSNicolas Dichtel {
254be42da0eSNicolas Dichtel 	struct ip_tunnel *t = netdev_priv(dev);
255be42da0eSNicolas Dichtel 	struct net *net = dev_net(dev);
256be42da0eSNicolas Dichtel 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
257be42da0eSNicolas Dichtel 	int err;
258be42da0eSNicolas Dichtel 
259be42da0eSNicolas Dichtel 	err = ipip_tunnel_init(dev);
260be42da0eSNicolas Dichtel 	if (err < 0)
261be42da0eSNicolas Dichtel 		goto out;
262be42da0eSNicolas Dichtel 
263be42da0eSNicolas Dichtel 	err = register_netdevice(dev);
264be42da0eSNicolas Dichtel 	if (err < 0)
265be42da0eSNicolas Dichtel 		goto out;
266be42da0eSNicolas Dichtel 
267be42da0eSNicolas Dichtel 	strcpy(t->parms.name, dev->name);
268be42da0eSNicolas Dichtel 	dev->rtnl_link_ops = &ipip_link_ops;
269be42da0eSNicolas Dichtel 
270be42da0eSNicolas Dichtel 	dev_hold(dev);
271be42da0eSNicolas Dichtel 	ipip_tunnel_link(ipn, t);
272be42da0eSNicolas Dichtel 	return 0;
273be42da0eSNicolas Dichtel 
274be42da0eSNicolas Dichtel out:
275be42da0eSNicolas Dichtel 	return err;
276be42da0eSNicolas Dichtel }
277be42da0eSNicolas Dichtel 
278b9fae5c9SPavel Emelyanov static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
279b9fae5c9SPavel Emelyanov 		struct ip_tunnel_parm *parms, int create)
2801da177e4SLinus Torvalds {
281d5a0a1e3SAl Viro 	__be32 remote = parms->iph.daddr;
282d5a0a1e3SAl Viro 	__be32 local = parms->iph.saddr;
283b7285b79SEric Dumazet 	struct ip_tunnel *t, *nt;
284b7285b79SEric Dumazet 	struct ip_tunnel __rcu **tp;
2851da177e4SLinus Torvalds 	struct net_device *dev;
2861da177e4SLinus Torvalds 	char name[IFNAMSIZ];
287b9fae5c9SPavel Emelyanov 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
2881da177e4SLinus Torvalds 
289b7285b79SEric Dumazet 	for (tp = __ipip_bucket(ipn, parms);
290b7285b79SEric Dumazet 		 (t = rtnl_dereference(*tp)) != NULL;
291b7285b79SEric Dumazet 		 tp = &t->next) {
2921da177e4SLinus Torvalds 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
2931da177e4SLinus Torvalds 			return t;
2941da177e4SLinus Torvalds 	}
2951da177e4SLinus Torvalds 	if (!create)
2961da177e4SLinus Torvalds 		return NULL;
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	if (parms->name[0])
2991da177e4SLinus Torvalds 		strlcpy(name, parms->name, IFNAMSIZ);
30034cc7ba6SPavel Emelyanov 	else
3013c97af99SEric Dumazet 		strcpy(name, "tunl%d");
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup);
3041da177e4SLinus Torvalds 	if (dev == NULL)
3051da177e4SLinus Torvalds 		return NULL;
3061da177e4SLinus Torvalds 
3070a826406SPavel Emelyanov 	dev_net_set(dev, net);
3080a826406SPavel Emelyanov 
3092941a486SPatrick McHardy 	nt = netdev_priv(dev);
3101da177e4SLinus Torvalds 	nt->parms = *parms;
3111da177e4SLinus Torvalds 
312be42da0eSNicolas Dichtel 	if (ipip_tunnel_create(dev) < 0)
3133c97af99SEric Dumazet 		goto failed_free;
31423a12b14SStephen Hemminger 
3151da177e4SLinus Torvalds 	return nt;
3161da177e4SLinus Torvalds 
317b37d428bSPavel Emelyanov failed_free:
3183c97af99SEric Dumazet 	ipip_dev_free(dev);
3191da177e4SLinus Torvalds 	return NULL;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds 
322b7285b79SEric Dumazet /* called with RTNL */
3231da177e4SLinus Torvalds static void ipip_tunnel_uninit(struct net_device *dev)
3241da177e4SLinus Torvalds {
325b9855c54SPavel Emelyanov 	struct net *net = dev_net(dev);
326b9855c54SPavel Emelyanov 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
327b9855c54SPavel Emelyanov 
328b7285b79SEric Dumazet 	if (dev == ipn->fb_tunnel_dev)
329a9b3cd7fSStephen Hemminger 		RCU_INIT_POINTER(ipn->tunnels_wc[0], NULL);
330b7285b79SEric Dumazet 	else
331b9fae5c9SPavel Emelyanov 		ipip_tunnel_unlink(ipn, netdev_priv(dev));
3321da177e4SLinus Torvalds 	dev_put(dev);
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
335d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info)
3361da177e4SLinus Torvalds {
3371da177e4SLinus Torvalds 
338071f92d0SRami Rosen /* All the routers (except for Linux) return only
3391da177e4SLinus Torvalds    8 bytes of packet payload. It means, that precise relaying of
3401da177e4SLinus Torvalds    ICMP in the real Internet is absolutely infeasible.
3411da177e4SLinus Torvalds  */
342b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
34388c7664fSArnaldo Carvalho de Melo 	const int type = icmp_hdr(skb)->type;
34488c7664fSArnaldo Carvalho de Melo 	const int code = icmp_hdr(skb)->code;
3451da177e4SLinus Torvalds 	struct ip_tunnel *t;
346d2acc347SHerbert Xu 	int err;
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	switch (type) {
3491da177e4SLinus Torvalds 	default:
3501da177e4SLinus Torvalds 	case ICMP_PARAMETERPROB:
351d2acc347SHerbert Xu 		return 0;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	case ICMP_DEST_UNREACH:
3541da177e4SLinus Torvalds 		switch (code) {
3551da177e4SLinus Torvalds 		case ICMP_SR_FAILED:
3561da177e4SLinus Torvalds 		case ICMP_PORT_UNREACH:
3571da177e4SLinus Torvalds 			/* Impossible event. */
358d2acc347SHerbert Xu 			return 0;
3591da177e4SLinus Torvalds 		default:
3601da177e4SLinus Torvalds 			/* All others are translated to HOST_UNREACH.
3611da177e4SLinus Torvalds 			   rfc2003 contains "deep thoughts" about NET_UNREACH,
3621da177e4SLinus Torvalds 			   I believe they are just ether pollution. --ANK
3631da177e4SLinus Torvalds 			 */
3641da177e4SLinus Torvalds 			break;
3651da177e4SLinus Torvalds 		}
3661da177e4SLinus Torvalds 		break;
3671da177e4SLinus Torvalds 	case ICMP_TIME_EXCEEDED:
3681da177e4SLinus Torvalds 		if (code != ICMP_EXC_TTL)
369d2acc347SHerbert Xu 			return 0;
3701da177e4SLinus Torvalds 		break;
37155be7a9cSDavid S. Miller 	case ICMP_REDIRECT:
37255be7a9cSDavid S. Miller 		break;
3731da177e4SLinus Torvalds 	}
3741da177e4SLinus Torvalds 
375d2acc347SHerbert Xu 	err = -ENOENT;
376cec3ffaeSPavel Emelyanov 	t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
37736393395SDavid S. Miller 	if (t == NULL)
37836393395SDavid S. Miller 		goto out;
37936393395SDavid S. Miller 
38036393395SDavid S. Miller 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
38136393395SDavid S. Miller 		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
38236393395SDavid S. Miller 				 t->dev->ifindex, 0, IPPROTO_IPIP, 0);
38336393395SDavid S. Miller 		err = 0;
38436393395SDavid S. Miller 		goto out;
38536393395SDavid S. Miller 	}
38636393395SDavid S. Miller 
38755be7a9cSDavid S. Miller 	if (type == ICMP_REDIRECT) {
38855be7a9cSDavid S. Miller 		ipv4_redirect(skb, dev_net(skb->dev), t->dev->ifindex, 0,
38955be7a9cSDavid S. Miller 			      IPPROTO_IPIP, 0);
39055be7a9cSDavid S. Miller 		err = 0;
39155be7a9cSDavid S. Miller 		goto out;
39255be7a9cSDavid S. Miller 	}
39355be7a9cSDavid S. Miller 
39436393395SDavid S. Miller 	if (t->parms.iph.daddr == 0)
3951da177e4SLinus Torvalds 		goto out;
396d2acc347SHerbert Xu 
397d2acc347SHerbert Xu 	err = 0;
3981da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
3991da177e4SLinus Torvalds 		goto out;
4001da177e4SLinus Torvalds 
40126d94b46SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
4021da177e4SLinus Torvalds 		t->err_count++;
4031da177e4SLinus Torvalds 	else
4041da177e4SLinus Torvalds 		t->err_count = 1;
4051da177e4SLinus Torvalds 	t->err_time = jiffies;
4061da177e4SLinus Torvalds out:
407b0558ef2Sstephen hemminger 
408d2acc347SHerbert Xu 	return err;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds static int ipip_rcv(struct sk_buff *skb)
4121da177e4SLinus Torvalds {
4131da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
414eddc9ec5SArnaldo Carvalho de Melo 	const struct iphdr *iph = ip_hdr(skb);
415eccc1bb8Sstephen hemminger 	int err;
4161da177e4SLinus Torvalds 
4173c97af99SEric Dumazet 	tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr);
4183c97af99SEric Dumazet 	if (tunnel != NULL) {
4193c97af99SEric Dumazet 		struct pcpu_tstats *tstats;
4203c97af99SEric Dumazet 
421eccc1bb8Sstephen hemminger 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
422eccc1bb8Sstephen hemminger 			goto drop;
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 		secpath_reset(skb);
4251da177e4SLinus Torvalds 
426b0e380b1SArnaldo Carvalho de Melo 		skb->mac_header = skb->network_header;
427c1d2bbe1SArnaldo Carvalho de Melo 		skb_reset_network_header(skb);
4281da177e4SLinus Torvalds 		skb->protocol = htons(ETH_P_IP);
4291da177e4SLinus Torvalds 		skb->pkt_type = PACKET_HOST;
4301da177e4SLinus Torvalds 
431eccc1bb8Sstephen hemminger 		__skb_tunnel_rx(skb, tunnel->dev);
432eccc1bb8Sstephen hemminger 
433eccc1bb8Sstephen hemminger 		err = IP_ECN_decapsulate(iph, skb);
434eccc1bb8Sstephen hemminger 		if (unlikely(err)) {
435eccc1bb8Sstephen hemminger 			if (log_ecn_error)
436eccc1bb8Sstephen hemminger 				net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
437eccc1bb8Sstephen hemminger 						     &iph->saddr, iph->tos);
438eccc1bb8Sstephen hemminger 			if (err > 1) {
439eccc1bb8Sstephen hemminger 				++tunnel->dev->stats.rx_frame_errors;
440eccc1bb8Sstephen hemminger 				++tunnel->dev->stats.rx_errors;
441eccc1bb8Sstephen hemminger 				goto drop;
442eccc1bb8Sstephen hemminger 			}
443eccc1bb8Sstephen hemminger 		}
444eccc1bb8Sstephen hemminger 
4453c97af99SEric Dumazet 		tstats = this_cpu_ptr(tunnel->dev->tstats);
44687b6d218Sstephen hemminger 		u64_stats_update_begin(&tstats->syncp);
4473c97af99SEric Dumazet 		tstats->rx_packets++;
4483c97af99SEric Dumazet 		tstats->rx_bytes += skb->len;
44987b6d218Sstephen hemminger 		u64_stats_update_end(&tstats->syncp);
4503c97af99SEric Dumazet 
451caf586e5SEric Dumazet 		netif_rx(skb);
4521da177e4SLinus Torvalds 		return 0;
4531da177e4SLinus Torvalds 	}
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	return -1;
456eccc1bb8Sstephen hemminger 
457eccc1bb8Sstephen hemminger drop:
458eccc1bb8Sstephen hemminger 	kfree_skb(skb);
459eccc1bb8Sstephen hemminger 	return 0;
4601da177e4SLinus Torvalds }
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds /*
4631da177e4SLinus Torvalds  *	This function assumes it is being called from dev_queue_xmit()
4641da177e4SLinus Torvalds  *	and that skb is filled properly by that function.
4651da177e4SLinus Torvalds  */
4661da177e4SLinus Torvalds 
4676fef4c0cSStephen Hemminger static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
4681da177e4SLinus Torvalds {
4692941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
470b71d1d42SEric Dumazet 	const struct iphdr  *tiph = &tunnel->parms.iph;
4711da177e4SLinus Torvalds 	u8     tos = tunnel->parms.iph.tos;
472d5a0a1e3SAl Viro 	__be16 df = tiph->frag_off;
4731da177e4SLinus Torvalds 	struct rtable *rt;     			/* Route to the other host */
4741da177e4SLinus Torvalds 	struct net_device *tdev;		/* Device to other host */
475cef401deSEric Dumazet 	const struct iphdr  *old_iph;
4761da177e4SLinus Torvalds 	struct iphdr  *iph;			/* Our new IP header */
477c2636b4dSChuck Lever 	unsigned int max_headroom;		/* The extra header space needed */
478d5a0a1e3SAl Viro 	__be32 dst = tiph->daddr;
47931e4543dSDavid S. Miller 	struct flowi4 fl4;
4801da177e4SLinus Torvalds 	int    mtu;
4818344bfc6SPravin B Shelar 	int err;
4828344bfc6SPravin B Shelar 	int pkt_len;
4831da177e4SLinus Torvalds 
4841da177e4SLinus Torvalds 	if (skb->protocol != htons(ETH_P_IP))
4851da177e4SLinus Torvalds 		goto tx_error;
486cef401deSEric Dumazet 	old_iph = ip_hdr(skb);
487cef401deSEric Dumazet 
4881da177e4SLinus Torvalds 	if (tos & 1)
4891da177e4SLinus Torvalds 		tos = old_iph->tos;
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 	if (!dst) {
4921da177e4SLinus Torvalds 		/* NBMA tunnel */
493511c3f92SEric Dumazet 		if ((rt = skb_rtable(skb)) == NULL) {
4943c97af99SEric Dumazet 			dev->stats.tx_fifo_errors++;
4951da177e4SLinus Torvalds 			goto tx_error;
4961da177e4SLinus Torvalds 		}
497f8126f1dSDavid S. Miller 		dst = rt_nexthop(rt, old_iph->daddr);
4981da177e4SLinus Torvalds 	}
4991da177e4SLinus Torvalds 
50031e4543dSDavid S. Miller 	rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
50178fbfd8aSDavid S. Miller 				   dst, tiph->saddr,
50278fbfd8aSDavid S. Miller 				   0, 0,
50378fbfd8aSDavid S. Miller 				   IPPROTO_IPIP, RT_TOS(tos),
50478fbfd8aSDavid S. Miller 				   tunnel->parms.link);
505b23dd4feSDavid S. Miller 	if (IS_ERR(rt)) {
5063c97af99SEric Dumazet 		dev->stats.tx_carrier_errors++;
5071da177e4SLinus Torvalds 		goto tx_error_icmp;
5081da177e4SLinus Torvalds 	}
509d8d1f30bSChangli Gao 	tdev = rt->dst.dev;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	if (tdev == dev) {
5121da177e4SLinus Torvalds 		ip_rt_put(rt);
5133c97af99SEric Dumazet 		dev->stats.collisions++;
5141da177e4SLinus Torvalds 		goto tx_error;
5151da177e4SLinus Torvalds 	}
5161da177e4SLinus Torvalds 
51723ca0c98SHerbert Xu 	df |= old_iph->frag_off & htons(IP_DF);
51823ca0c98SHerbert Xu 
51923ca0c98SHerbert Xu 	if (df) {
520d8d1f30bSChangli Gao 		mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 		if (mtu < 68) {
5233c97af99SEric Dumazet 			dev->stats.collisions++;
5241da177e4SLinus Torvalds 			ip_rt_put(rt);
5251da177e4SLinus Torvalds 			goto tx_error;
5261da177e4SLinus Torvalds 		}
52723ca0c98SHerbert Xu 
528adf30907SEric Dumazet 		if (skb_dst(skb))
5296700c270SDavid S. Miller 			skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
5301da177e4SLinus Torvalds 
53123ca0c98SHerbert Xu 		if ((old_iph->frag_off & htons(IP_DF)) &&
53223ca0c98SHerbert Xu 		    mtu < ntohs(old_iph->tot_len)) {
53323ca0c98SHerbert Xu 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
53423ca0c98SHerbert Xu 				  htonl(mtu));
5351da177e4SLinus Torvalds 			ip_rt_put(rt);
5361da177e4SLinus Torvalds 			goto tx_error;
5371da177e4SLinus Torvalds 		}
53823ca0c98SHerbert Xu 	}
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 	if (tunnel->err_count > 0) {
54126d94b46SWei Yongjun 		if (time_before(jiffies,
54226d94b46SWei Yongjun 				tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
5431da177e4SLinus Torvalds 			tunnel->err_count--;
5441da177e4SLinus Torvalds 			dst_link_failure(skb);
5451da177e4SLinus Torvalds 		} else
5461da177e4SLinus Torvalds 			tunnel->err_count = 0;
5471da177e4SLinus Torvalds 	}
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	/*
5501da177e4SLinus Torvalds 	 * Okay, now see if we can stuff it in the buffer as-is.
5511da177e4SLinus Torvalds 	 */
5521da177e4SLinus Torvalds 	max_headroom = (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr));
5531da177e4SLinus Torvalds 
554cfbba49dSPatrick McHardy 	if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
555cfbba49dSPatrick McHardy 	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
5561da177e4SLinus Torvalds 		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
5571da177e4SLinus Torvalds 		if (!new_skb) {
5581da177e4SLinus Torvalds 			ip_rt_put(rt);
5593c97af99SEric Dumazet 			dev->stats.tx_dropped++;
5601da177e4SLinus Torvalds 			dev_kfree_skb(skb);
5616ed10654SPatrick McHardy 			return NETDEV_TX_OK;
5621da177e4SLinus Torvalds 		}
5631da177e4SLinus Torvalds 		if (skb->sk)
5641da177e4SLinus Torvalds 			skb_set_owner_w(new_skb, skb->sk);
5651da177e4SLinus Torvalds 		dev_kfree_skb(skb);
5661da177e4SLinus Torvalds 		skb = new_skb;
567eddc9ec5SArnaldo Carvalho de Melo 		old_iph = ip_hdr(skb);
5681da177e4SLinus Torvalds 	}
5691da177e4SLinus Torvalds 
570*4f3ed920SPravin B Shelar 	if (!skb->encapsulation) {
571*4f3ed920SPravin B Shelar 		skb_reset_inner_headers(skb);
572*4f3ed920SPravin B Shelar 		skb->encapsulation = 1;
573*4f3ed920SPravin B Shelar 	}
574*4f3ed920SPravin B Shelar 	if (skb->ip_summed != CHECKSUM_PARTIAL)
575*4f3ed920SPravin B Shelar 		skb->ip_summed = CHECKSUM_NONE;
576*4f3ed920SPravin B Shelar 
577b0e380b1SArnaldo Carvalho de Melo 	skb->transport_header = skb->network_header;
578e2d1bca7SArnaldo Carvalho de Melo 	skb_push(skb, sizeof(struct iphdr));
579e2d1bca7SArnaldo Carvalho de Melo 	skb_reset_network_header(skb);
5801da177e4SLinus Torvalds 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
58148d5cad8SPatrick McHardy 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
58248d5cad8SPatrick McHardy 			      IPSKB_REROUTED);
583adf30907SEric Dumazet 	skb_dst_drop(skb);
584d8d1f30bSChangli Gao 	skb_dst_set(skb, &rt->dst);
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 	/*
5871da177e4SLinus Torvalds 	 *	Push down and install the IPIP header.
5881da177e4SLinus Torvalds 	 */
5891da177e4SLinus Torvalds 
590eddc9ec5SArnaldo Carvalho de Melo 	iph 			=	ip_hdr(skb);
5911da177e4SLinus Torvalds 	iph->version		=	4;
5921da177e4SLinus Torvalds 	iph->ihl		=	sizeof(struct iphdr)>>2;
5931da177e4SLinus Torvalds 	iph->frag_off		=	df;
5941da177e4SLinus Torvalds 	iph->protocol		=	IPPROTO_IPIP;
5951da177e4SLinus Torvalds 	iph->tos		=	INET_ECN_encapsulate(tos, old_iph->tos);
59669458cb1SDavid S. Miller 	iph->daddr		=	fl4.daddr;
59769458cb1SDavid S. Miller 	iph->saddr		=	fl4.saddr;
5988344bfc6SPravin B Shelar 	tunnel_ip_select_ident(skb, old_iph, &rt->dst);
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 	if ((iph->ttl = tiph->ttl) == 0)
6011da177e4SLinus Torvalds 		iph->ttl	=	old_iph->ttl;
6021da177e4SLinus Torvalds 
6038344bfc6SPravin B Shelar 	nf_reset(skb);
6048344bfc6SPravin B Shelar 
6058344bfc6SPravin B Shelar 	pkt_len = skb->len - skb_transport_offset(skb);
6068344bfc6SPravin B Shelar 	err = ip_local_out(skb);
6078344bfc6SPravin B Shelar 	if (likely(net_xmit_eval(err) == 0)) {
6088344bfc6SPravin B Shelar 		struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats);
6098344bfc6SPravin B Shelar 
6108344bfc6SPravin B Shelar 		u64_stats_update_begin(&tstats->syncp);
6118344bfc6SPravin B Shelar 		tstats->tx_bytes += pkt_len;
6128344bfc6SPravin B Shelar 		tstats->tx_packets++;
6138344bfc6SPravin B Shelar 		u64_stats_update_end(&tstats->syncp);
6148344bfc6SPravin B Shelar 	} else {
6158344bfc6SPravin B Shelar 		dev->stats.tx_errors++;
6168344bfc6SPravin B Shelar 		dev->stats.tx_aborted_errors++;
6178344bfc6SPravin B Shelar 	}
6188344bfc6SPravin B Shelar 
6196ed10654SPatrick McHardy 	return NETDEV_TX_OK;
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds tx_error_icmp:
6221da177e4SLinus Torvalds 	dst_link_failure(skb);
6231da177e4SLinus Torvalds tx_error:
6243c97af99SEric Dumazet 	dev->stats.tx_errors++;
6251da177e4SLinus Torvalds 	dev_kfree_skb(skb);
6266ed10654SPatrick McHardy 	return NETDEV_TX_OK;
6271da177e4SLinus Torvalds }
6281da177e4SLinus Torvalds 
6295533995bSMichal Schmidt static void ipip_tunnel_bind_dev(struct net_device *dev)
6305533995bSMichal Schmidt {
6315533995bSMichal Schmidt 	struct net_device *tdev = NULL;
6325533995bSMichal Schmidt 	struct ip_tunnel *tunnel;
633b71d1d42SEric Dumazet 	const struct iphdr *iph;
6345533995bSMichal Schmidt 
6355533995bSMichal Schmidt 	tunnel = netdev_priv(dev);
6365533995bSMichal Schmidt 	iph = &tunnel->parms.iph;
6375533995bSMichal Schmidt 
6385533995bSMichal Schmidt 	if (iph->daddr) {
63931e4543dSDavid S. Miller 		struct rtable *rt;
64031e4543dSDavid S. Miller 		struct flowi4 fl4;
64131e4543dSDavid S. Miller 
64231e4543dSDavid S. Miller 		rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
64378fbfd8aSDavid S. Miller 					   iph->daddr, iph->saddr,
64478fbfd8aSDavid S. Miller 					   0, 0,
64578fbfd8aSDavid S. Miller 					   IPPROTO_IPIP,
64678fbfd8aSDavid S. Miller 					   RT_TOS(iph->tos),
64778fbfd8aSDavid S. Miller 					   tunnel->parms.link);
648b23dd4feSDavid S. Miller 		if (!IS_ERR(rt)) {
649d8d1f30bSChangli Gao 			tdev = rt->dst.dev;
6505533995bSMichal Schmidt 			ip_rt_put(rt);
6515533995bSMichal Schmidt 		}
6525533995bSMichal Schmidt 		dev->flags |= IFF_POINTOPOINT;
6535533995bSMichal Schmidt 	}
6545533995bSMichal Schmidt 
6555533995bSMichal Schmidt 	if (!tdev && tunnel->parms.link)
656b99f0152SPavel Emelyanov 		tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
6575533995bSMichal Schmidt 
6585533995bSMichal Schmidt 	if (tdev) {
6595533995bSMichal Schmidt 		dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
6605533995bSMichal Schmidt 		dev->mtu = tdev->mtu - sizeof(struct iphdr);
6615533995bSMichal Schmidt 	}
6625533995bSMichal Schmidt 	dev->iflink = tunnel->parms.link;
6635533995bSMichal Schmidt }
6645533995bSMichal Schmidt 
665be42da0eSNicolas Dichtel static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
666be42da0eSNicolas Dichtel {
667be42da0eSNicolas Dichtel 	struct net *net = dev_net(t->dev);
668be42da0eSNicolas Dichtel 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
669be42da0eSNicolas Dichtel 
670be42da0eSNicolas Dichtel 	ipip_tunnel_unlink(ipn, t);
671be42da0eSNicolas Dichtel 	synchronize_net();
672be42da0eSNicolas Dichtel 	t->parms.iph.saddr = p->iph.saddr;
673be42da0eSNicolas Dichtel 	t->parms.iph.daddr = p->iph.daddr;
674be42da0eSNicolas Dichtel 	memcpy(t->dev->dev_addr, &p->iph.saddr, 4);
675be42da0eSNicolas Dichtel 	memcpy(t->dev->broadcast, &p->iph.daddr, 4);
676be42da0eSNicolas Dichtel 	ipip_tunnel_link(ipn, t);
677be42da0eSNicolas Dichtel 	t->parms.iph.ttl = p->iph.ttl;
678be42da0eSNicolas Dichtel 	t->parms.iph.tos = p->iph.tos;
679be42da0eSNicolas Dichtel 	t->parms.iph.frag_off = p->iph.frag_off;
680be42da0eSNicolas Dichtel 	if (t->parms.link != p->link) {
681be42da0eSNicolas Dichtel 		t->parms.link = p->link;
682be42da0eSNicolas Dichtel 		ipip_tunnel_bind_dev(t->dev);
683be42da0eSNicolas Dichtel 	}
684be42da0eSNicolas Dichtel 	netdev_state_change(t->dev);
685be42da0eSNicolas Dichtel }
686be42da0eSNicolas Dichtel 
6871da177e4SLinus Torvalds static int
6881da177e4SLinus Torvalds ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds 	int err = 0;
6911da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
6921da177e4SLinus Torvalds 	struct ip_tunnel *t;
693b9855c54SPavel Emelyanov 	struct net *net = dev_net(dev);
694b9855c54SPavel Emelyanov 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	switch (cmd) {
6971da177e4SLinus Torvalds 	case SIOCGETTUNNEL:
6981da177e4SLinus Torvalds 		t = NULL;
699b9855c54SPavel Emelyanov 		if (dev == ipn->fb_tunnel_dev) {
7001da177e4SLinus Torvalds 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
7011da177e4SLinus Torvalds 				err = -EFAULT;
7021da177e4SLinus Torvalds 				break;
7031da177e4SLinus Torvalds 			}
704b9fae5c9SPavel Emelyanov 			t = ipip_tunnel_locate(net, &p, 0);
7051da177e4SLinus Torvalds 		}
7061da177e4SLinus Torvalds 		if (t == NULL)
7072941a486SPatrick McHardy 			t = netdev_priv(dev);
7081da177e4SLinus Torvalds 		memcpy(&p, &t->parms, sizeof(p));
7091da177e4SLinus Torvalds 		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
7101da177e4SLinus Torvalds 			err = -EFAULT;
7111da177e4SLinus Torvalds 		break;
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	case SIOCADDTUNNEL:
7141da177e4SLinus Torvalds 	case SIOCCHGTUNNEL:
7151da177e4SLinus Torvalds 		err = -EPERM;
71652e804c6SEric W. Biederman 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
7171da177e4SLinus Torvalds 			goto done;
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 		err = -EFAULT;
7201da177e4SLinus Torvalds 		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
7211da177e4SLinus Torvalds 			goto done;
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds 		err = -EINVAL;
7241da177e4SLinus Torvalds 		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
7251da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
7261da177e4SLinus Torvalds 			goto done;
7271da177e4SLinus Torvalds 		if (p.iph.ttl)
7281da177e4SLinus Torvalds 			p.iph.frag_off |= htons(IP_DF);
7291da177e4SLinus Torvalds 
730b9fae5c9SPavel Emelyanov 		t = ipip_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
7311da177e4SLinus Torvalds 
732b9855c54SPavel Emelyanov 		if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
7331da177e4SLinus Torvalds 			if (t != NULL) {
7341da177e4SLinus Torvalds 				if (t->dev != dev) {
7351da177e4SLinus Torvalds 					err = -EEXIST;
7361da177e4SLinus Torvalds 					break;
7371da177e4SLinus Torvalds 				}
7381da177e4SLinus Torvalds 			} else {
7391da177e4SLinus Torvalds 				if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
7401da177e4SLinus Torvalds 				    (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
7411da177e4SLinus Torvalds 					err = -EINVAL;
7421da177e4SLinus Torvalds 					break;
7431da177e4SLinus Torvalds 				}
7442941a486SPatrick McHardy 				t = netdev_priv(dev);
745c38cc4b5SNicolas Dichtel 			}
746c38cc4b5SNicolas Dichtel 
747be42da0eSNicolas Dichtel 			ipip_tunnel_update(t, &p);
7485533995bSMichal Schmidt 		}
749c38cc4b5SNicolas Dichtel 
750c38cc4b5SNicolas Dichtel 		if (t) {
751c38cc4b5SNicolas Dichtel 			err = 0;
7521da177e4SLinus Torvalds 			if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
7531da177e4SLinus Torvalds 				err = -EFAULT;
7541da177e4SLinus Torvalds 		} else
7551da177e4SLinus Torvalds 			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
7561da177e4SLinus Torvalds 		break;
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 	case SIOCDELTUNNEL:
7591da177e4SLinus Torvalds 		err = -EPERM;
76052e804c6SEric W. Biederman 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
7611da177e4SLinus Torvalds 			goto done;
7621da177e4SLinus Torvalds 
763b9855c54SPavel Emelyanov 		if (dev == ipn->fb_tunnel_dev) {
7641da177e4SLinus Torvalds 			err = -EFAULT;
7651da177e4SLinus Torvalds 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
7661da177e4SLinus Torvalds 				goto done;
7671da177e4SLinus Torvalds 			err = -ENOENT;
768b9fae5c9SPavel Emelyanov 			if ((t = ipip_tunnel_locate(net, &p, 0)) == NULL)
7691da177e4SLinus Torvalds 				goto done;
7701da177e4SLinus Torvalds 			err = -EPERM;
771b9855c54SPavel Emelyanov 			if (t->dev == ipn->fb_tunnel_dev)
7721da177e4SLinus Torvalds 				goto done;
7731da177e4SLinus Torvalds 			dev = t->dev;
7741da177e4SLinus Torvalds 		}
77522f8cde5SStephen Hemminger 		unregister_netdevice(dev);
77622f8cde5SStephen Hemminger 		err = 0;
7771da177e4SLinus Torvalds 		break;
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 	default:
7801da177e4SLinus Torvalds 		err = -EINVAL;
7811da177e4SLinus Torvalds 	}
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds done:
7841da177e4SLinus Torvalds 	return err;
7851da177e4SLinus Torvalds }
7861da177e4SLinus Torvalds 
7871da177e4SLinus Torvalds static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
7881da177e4SLinus Torvalds {
7891da177e4SLinus Torvalds 	if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
7901da177e4SLinus Torvalds 		return -EINVAL;
7911da177e4SLinus Torvalds 	dev->mtu = new_mtu;
7921da177e4SLinus Torvalds 	return 0;
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds 
79523a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = {
79623a12b14SStephen Hemminger 	.ndo_uninit	= ipip_tunnel_uninit,
79723a12b14SStephen Hemminger 	.ndo_start_xmit	= ipip_tunnel_xmit,
79823a12b14SStephen Hemminger 	.ndo_do_ioctl	= ipip_tunnel_ioctl,
79923a12b14SStephen Hemminger 	.ndo_change_mtu	= ipip_tunnel_change_mtu,
80087b6d218Sstephen hemminger 	.ndo_get_stats64 = ipip_get_stats64,
80123a12b14SStephen Hemminger };
80223a12b14SStephen Hemminger 
8033c97af99SEric Dumazet static void ipip_dev_free(struct net_device *dev)
8043c97af99SEric Dumazet {
8053c97af99SEric Dumazet 	free_percpu(dev->tstats);
8063c97af99SEric Dumazet 	free_netdev(dev);
8073c97af99SEric Dumazet }
8083c97af99SEric Dumazet 
809c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG |		\
810c3b89fbbSEric Dumazet 		       NETIF_F_FRAGLIST |	\
811c3b89fbbSEric Dumazet 		       NETIF_F_HIGHDMA |	\
812c3b89fbbSEric Dumazet 		       NETIF_F_HW_CSUM)
813c3b89fbbSEric Dumazet 
8141da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev)
8151da177e4SLinus Torvalds {
81623a12b14SStephen Hemminger 	dev->netdev_ops		= &ipip_netdev_ops;
8173c97af99SEric Dumazet 	dev->destructor		= ipip_dev_free;
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	dev->type		= ARPHRD_TUNNEL;
8201da177e4SLinus Torvalds 	dev->hard_header_len 	= LL_MAX_HEADER + sizeof(struct iphdr);
82146f25dffSKris Katterjohn 	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr);
8221da177e4SLinus Torvalds 	dev->flags		= IFF_NOARP;
8231da177e4SLinus Torvalds 	dev->iflink		= 0;
8241da177e4SLinus Torvalds 	dev->addr_len		= 4;
8250a826406SPavel Emelyanov 	dev->features		|= NETIF_F_NETNS_LOCAL;
826153f0943SEric Dumazet 	dev->features		|= NETIF_F_LLTX;
82728e72216SEric Dumazet 	dev->priv_flags		&= ~IFF_XMIT_DST_RELEASE;
828c3b89fbbSEric Dumazet 
829c3b89fbbSEric Dumazet 	dev->features		|= IPIP_FEATURES;
830c3b89fbbSEric Dumazet 	dev->hw_features	|= IPIP_FEATURES;
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds 
8333c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev)
8341da177e4SLinus Torvalds {
83523a12b14SStephen Hemminger 	struct ip_tunnel *tunnel = netdev_priv(dev);
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	tunnel->dev = dev;
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
8401da177e4SLinus Torvalds 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
8411da177e4SLinus Torvalds 
8425533995bSMichal Schmidt 	ipip_tunnel_bind_dev(dev);
8433c97af99SEric Dumazet 
8443c97af99SEric Dumazet 	dev->tstats = alloc_percpu(struct pcpu_tstats);
8453c97af99SEric Dumazet 	if (!dev->tstats)
8463c97af99SEric Dumazet 		return -ENOMEM;
8473c97af99SEric Dumazet 
8483c97af99SEric Dumazet 	return 0;
8491da177e4SLinus Torvalds }
8501da177e4SLinus Torvalds 
851fada5636SEric Dumazet static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
8521da177e4SLinus Torvalds {
8532941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
8541da177e4SLinus Torvalds 	struct iphdr *iph = &tunnel->parms.iph;
85544d3c299SPavel Emelyanov 	struct ipip_net *ipn = net_generic(dev_net(dev), ipip_net_id);
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds 	tunnel->dev = dev;
8581da177e4SLinus Torvalds 	strcpy(tunnel->parms.name, dev->name);
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds 	iph->version		= 4;
8611da177e4SLinus Torvalds 	iph->protocol		= IPPROTO_IPIP;
8621da177e4SLinus Torvalds 	iph->ihl		= 5;
8631da177e4SLinus Torvalds 
864fada5636SEric Dumazet 	dev->tstats = alloc_percpu(struct pcpu_tstats);
865fada5636SEric Dumazet 	if (!dev->tstats)
866fada5636SEric Dumazet 		return -ENOMEM;
867fada5636SEric Dumazet 
8681da177e4SLinus Torvalds 	dev_hold(dev);
869cf778b00SEric Dumazet 	rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
870fada5636SEric Dumazet 	return 0;
8711da177e4SLinus Torvalds }
8721da177e4SLinus Torvalds 
873be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[],
874be42da0eSNicolas Dichtel 			       struct ip_tunnel_parm *parms)
875be42da0eSNicolas Dichtel {
876be42da0eSNicolas Dichtel 	memset(parms, 0, sizeof(*parms));
877be42da0eSNicolas Dichtel 
878be42da0eSNicolas Dichtel 	parms->iph.version = 4;
879be42da0eSNicolas Dichtel 	parms->iph.protocol = IPPROTO_IPIP;
880be42da0eSNicolas Dichtel 	parms->iph.ihl = 5;
881be42da0eSNicolas Dichtel 
882be42da0eSNicolas Dichtel 	if (!data)
883be42da0eSNicolas Dichtel 		return;
884be42da0eSNicolas Dichtel 
885be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_LINK])
886be42da0eSNicolas Dichtel 		parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
887be42da0eSNicolas Dichtel 
888be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_LOCAL])
889fea379b2SNicolas Dichtel 		parms->iph.saddr = nla_get_be32(data[IFLA_IPTUN_LOCAL]);
890be42da0eSNicolas Dichtel 
891be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_REMOTE])
892fea379b2SNicolas Dichtel 		parms->iph.daddr = nla_get_be32(data[IFLA_IPTUN_REMOTE]);
893be42da0eSNicolas Dichtel 
894be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_TTL]) {
895be42da0eSNicolas Dichtel 		parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
896be42da0eSNicolas Dichtel 		if (parms->iph.ttl)
897be42da0eSNicolas Dichtel 			parms->iph.frag_off = htons(IP_DF);
898be42da0eSNicolas Dichtel 	}
899be42da0eSNicolas Dichtel 
900be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_TOS])
901be42da0eSNicolas Dichtel 		parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
902be42da0eSNicolas Dichtel 
903be42da0eSNicolas Dichtel 	if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
904be42da0eSNicolas Dichtel 		parms->iph.frag_off = htons(IP_DF);
905be42da0eSNicolas Dichtel }
906be42da0eSNicolas Dichtel 
907be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev,
908be42da0eSNicolas Dichtel 			struct nlattr *tb[], struct nlattr *data[])
909be42da0eSNicolas Dichtel {
910be42da0eSNicolas Dichtel 	struct net *net = dev_net(dev);
911be42da0eSNicolas Dichtel 	struct ip_tunnel *nt;
912be42da0eSNicolas Dichtel 
913be42da0eSNicolas Dichtel 	nt = netdev_priv(dev);
914be42da0eSNicolas Dichtel 	ipip_netlink_parms(data, &nt->parms);
915be42da0eSNicolas Dichtel 
916be42da0eSNicolas Dichtel 	if (ipip_tunnel_locate(net, &nt->parms, 0))
917be42da0eSNicolas Dichtel 		return -EEXIST;
918be42da0eSNicolas Dichtel 
919be42da0eSNicolas Dichtel 	return ipip_tunnel_create(dev);
920be42da0eSNicolas Dichtel }
921be42da0eSNicolas Dichtel 
922be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
923be42da0eSNicolas Dichtel 			   struct nlattr *data[])
924be42da0eSNicolas Dichtel {
925be42da0eSNicolas Dichtel 	struct ip_tunnel *t;
926be42da0eSNicolas Dichtel 	struct ip_tunnel_parm p;
927be42da0eSNicolas Dichtel 	struct net *net = dev_net(dev);
928be42da0eSNicolas Dichtel 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
929be42da0eSNicolas Dichtel 
930be42da0eSNicolas Dichtel 	if (dev == ipn->fb_tunnel_dev)
931be42da0eSNicolas Dichtel 		return -EINVAL;
932be42da0eSNicolas Dichtel 
933be42da0eSNicolas Dichtel 	ipip_netlink_parms(data, &p);
934be42da0eSNicolas Dichtel 
935be42da0eSNicolas Dichtel 	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
936be42da0eSNicolas Dichtel 	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
937be42da0eSNicolas Dichtel 		return -EINVAL;
938be42da0eSNicolas Dichtel 
939be42da0eSNicolas Dichtel 	t = ipip_tunnel_locate(net, &p, 0);
940be42da0eSNicolas Dichtel 
941be42da0eSNicolas Dichtel 	if (t) {
942be42da0eSNicolas Dichtel 		if (t->dev != dev)
943be42da0eSNicolas Dichtel 			return -EEXIST;
944be42da0eSNicolas Dichtel 	} else
945be42da0eSNicolas Dichtel 		t = netdev_priv(dev);
946be42da0eSNicolas Dichtel 
947be42da0eSNicolas Dichtel 	ipip_tunnel_update(t, &p);
948be42da0eSNicolas Dichtel 	return 0;
949be42da0eSNicolas Dichtel }
950be42da0eSNicolas Dichtel 
9510974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev)
9520974658dSNicolas Dichtel {
9530974658dSNicolas Dichtel 	return
9540974658dSNicolas Dichtel 		/* IFLA_IPTUN_LINK */
9550974658dSNicolas Dichtel 		nla_total_size(4) +
9560974658dSNicolas Dichtel 		/* IFLA_IPTUN_LOCAL */
9570974658dSNicolas Dichtel 		nla_total_size(4) +
9580974658dSNicolas Dichtel 		/* IFLA_IPTUN_REMOTE */
9590974658dSNicolas Dichtel 		nla_total_size(4) +
9600974658dSNicolas Dichtel 		/* IFLA_IPTUN_TTL */
9610974658dSNicolas Dichtel 		nla_total_size(1) +
9620974658dSNicolas Dichtel 		/* IFLA_IPTUN_TOS */
9630974658dSNicolas Dichtel 		nla_total_size(1) +
964befe2aa1SNicolas Dichtel 		/* IFLA_IPTUN_PMTUDISC */
965befe2aa1SNicolas Dichtel 		nla_total_size(1) +
9660974658dSNicolas Dichtel 		0;
9670974658dSNicolas Dichtel }
9680974658dSNicolas Dichtel 
9690974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
9700974658dSNicolas Dichtel {
9710974658dSNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
9720974658dSNicolas Dichtel 	struct ip_tunnel_parm *parm = &tunnel->parms;
9730974658dSNicolas Dichtel 
9740974658dSNicolas Dichtel 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
9750974658dSNicolas Dichtel 	    nla_put_be32(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
9760974658dSNicolas Dichtel 	    nla_put_be32(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
9770974658dSNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
978befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
979befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
980befe2aa1SNicolas Dichtel 		       !!(parm->iph.frag_off & htons(IP_DF))))
9810974658dSNicolas Dichtel 		goto nla_put_failure;
9820974658dSNicolas Dichtel 	return 0;
9830974658dSNicolas Dichtel 
9840974658dSNicolas Dichtel nla_put_failure:
9850974658dSNicolas Dichtel 	return -EMSGSIZE;
9860974658dSNicolas Dichtel }
9870974658dSNicolas Dichtel 
988be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
989be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
990be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
991be42da0eSNicolas Dichtel 	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
992be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
993be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
994be42da0eSNicolas Dichtel 	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
995be42da0eSNicolas Dichtel };
996be42da0eSNicolas Dichtel 
9970974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = {
9980974658dSNicolas Dichtel 	.kind		= "ipip",
9990974658dSNicolas Dichtel 	.maxtype	= IFLA_IPTUN_MAX,
1000be42da0eSNicolas Dichtel 	.policy		= ipip_policy,
10010974658dSNicolas Dichtel 	.priv_size	= sizeof(struct ip_tunnel),
1002be42da0eSNicolas Dichtel 	.setup		= ipip_tunnel_setup,
1003be42da0eSNicolas Dichtel 	.newlink	= ipip_newlink,
1004be42da0eSNicolas Dichtel 	.changelink	= ipip_changelink,
10050974658dSNicolas Dichtel 	.get_size	= ipip_get_size,
10060974658dSNicolas Dichtel 	.fill_info	= ipip_fill_info,
10070974658dSNicolas Dichtel };
10080974658dSNicolas Dichtel 
10096dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = {
10101da177e4SLinus Torvalds 	.handler	=	ipip_rcv,
10111da177e4SLinus Torvalds 	.err_handler	=	ipip_err,
1012d2acc347SHerbert Xu 	.priority	=	1,
10131da177e4SLinus Torvalds };
10141da177e4SLinus Torvalds 
10155747a1aaSStephen Hemminger static const char banner[] __initconst =
10161da177e4SLinus Torvalds 	KERN_INFO "IPv4 over IPv4 tunneling driver\n";
10171da177e4SLinus Torvalds 
10180694c4c0SEric Dumazet static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
101944d3c299SPavel Emelyanov {
102044d3c299SPavel Emelyanov 	int prio;
102144d3c299SPavel Emelyanov 
102244d3c299SPavel Emelyanov 	for (prio = 1; prio < 4; prio++) {
102344d3c299SPavel Emelyanov 		int h;
102444d3c299SPavel Emelyanov 		for (h = 0; h < HASH_SIZE; h++) {
1025b7285b79SEric Dumazet 			struct ip_tunnel *t;
10260694c4c0SEric Dumazet 
1027b7285b79SEric Dumazet 			t = rtnl_dereference(ipn->tunnels[prio][h]);
10280694c4c0SEric Dumazet 			while (t != NULL) {
10290694c4c0SEric Dumazet 				unregister_netdevice_queue(t->dev, head);
1030b7285b79SEric Dumazet 				t = rtnl_dereference(t->next);
10310694c4c0SEric Dumazet 			}
103244d3c299SPavel Emelyanov 		}
103344d3c299SPavel Emelyanov 	}
103444d3c299SPavel Emelyanov }
103544d3c299SPavel Emelyanov 
10362c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net)
103710dc4c7bSPavel Emelyanov {
103886de8a63SEric W. Biederman 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
103972b36015STed Feng 	struct ip_tunnel *t;
104010dc4c7bSPavel Emelyanov 	int err;
104110dc4c7bSPavel Emelyanov 
104244d3c299SPavel Emelyanov 	ipn->tunnels[0] = ipn->tunnels_wc;
104344d3c299SPavel Emelyanov 	ipn->tunnels[1] = ipn->tunnels_l;
104444d3c299SPavel Emelyanov 	ipn->tunnels[2] = ipn->tunnels_r;
104544d3c299SPavel Emelyanov 	ipn->tunnels[3] = ipn->tunnels_r_l;
104644d3c299SPavel Emelyanov 
1047b9855c54SPavel Emelyanov 	ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
1048b9855c54SPavel Emelyanov 					   "tunl0",
1049b9855c54SPavel Emelyanov 					   ipip_tunnel_setup);
1050b9855c54SPavel Emelyanov 	if (!ipn->fb_tunnel_dev) {
1051b9855c54SPavel Emelyanov 		err = -ENOMEM;
1052b9855c54SPavel Emelyanov 		goto err_alloc_dev;
1053b9855c54SPavel Emelyanov 	}
1054be77e593SAlexey Dobriyan 	dev_net_set(ipn->fb_tunnel_dev, net);
1055b9855c54SPavel Emelyanov 
1056fada5636SEric Dumazet 	err = ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
1057fada5636SEric Dumazet 	if (err)
1058fada5636SEric Dumazet 		goto err_reg_dev;
1059b9855c54SPavel Emelyanov 
1060b9855c54SPavel Emelyanov 	if ((err = register_netdev(ipn->fb_tunnel_dev)))
1061b9855c54SPavel Emelyanov 		goto err_reg_dev;
1062b9855c54SPavel Emelyanov 
106372b36015STed Feng 	t = netdev_priv(ipn->fb_tunnel_dev);
106472b36015STed Feng 
106572b36015STed Feng 	strcpy(t->parms.name, ipn->fb_tunnel_dev->name);
106610dc4c7bSPavel Emelyanov 	return 0;
106710dc4c7bSPavel Emelyanov 
1068b9855c54SPavel Emelyanov err_reg_dev:
1069fada5636SEric Dumazet 	ipip_dev_free(ipn->fb_tunnel_dev);
1070b9855c54SPavel Emelyanov err_alloc_dev:
1071b9855c54SPavel Emelyanov 	/* nothing */
107210dc4c7bSPavel Emelyanov 	return err;
107310dc4c7bSPavel Emelyanov }
107410dc4c7bSPavel Emelyanov 
10752c8c1e72SAlexey Dobriyan static void __net_exit ipip_exit_net(struct net *net)
107610dc4c7bSPavel Emelyanov {
107786de8a63SEric W. Biederman 	struct ipip_net *ipn = net_generic(net, ipip_net_id);
10780694c4c0SEric Dumazet 	LIST_HEAD(list);
107910dc4c7bSPavel Emelyanov 
1080b9855c54SPavel Emelyanov 	rtnl_lock();
10810694c4c0SEric Dumazet 	ipip_destroy_tunnels(ipn, &list);
10820694c4c0SEric Dumazet 	unregister_netdevice_queue(ipn->fb_tunnel_dev, &list);
10830694c4c0SEric Dumazet 	unregister_netdevice_many(&list);
1084b9855c54SPavel Emelyanov 	rtnl_unlock();
108510dc4c7bSPavel Emelyanov }
108610dc4c7bSPavel Emelyanov 
108710dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = {
108810dc4c7bSPavel Emelyanov 	.init = ipip_init_net,
108910dc4c7bSPavel Emelyanov 	.exit = ipip_exit_net,
109086de8a63SEric W. Biederman 	.id   = &ipip_net_id,
109186de8a63SEric W. Biederman 	.size = sizeof(struct ipip_net),
109210dc4c7bSPavel Emelyanov };
109310dc4c7bSPavel Emelyanov 
10941da177e4SLinus Torvalds static int __init ipip_init(void)
10951da177e4SLinus Torvalds {
10961da177e4SLinus Torvalds 	int err;
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 	printk(banner);
10991da177e4SLinus Torvalds 
110086de8a63SEric W. Biederman 	err = register_pernet_device(&ipip_net_ops);
1101d5aa407fSAlexey Dobriyan 	if (err < 0)
1102d5aa407fSAlexey Dobriyan 		return err;
1103d5aa407fSAlexey Dobriyan 	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
1104d5aa407fSAlexey Dobriyan 	if (err < 0) {
1105058bd4d2SJoe Perches 		pr_info("%s: can't register tunnel\n", __func__);
11060974658dSNicolas Dichtel 		goto xfrm_tunnel_failed;
1107d5aa407fSAlexey Dobriyan 	}
11080974658dSNicolas Dichtel 	err = rtnl_link_register(&ipip_link_ops);
11090974658dSNicolas Dichtel 	if (err < 0)
11100974658dSNicolas Dichtel 		goto rtnl_link_failed;
11110974658dSNicolas Dichtel 
11120974658dSNicolas Dichtel out:
1113b9855c54SPavel Emelyanov 	return err;
11140974658dSNicolas Dichtel 
11150974658dSNicolas Dichtel rtnl_link_failed:
11160974658dSNicolas Dichtel 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
11170974658dSNicolas Dichtel xfrm_tunnel_failed:
11180974658dSNicolas Dichtel 	unregister_pernet_device(&ipip_net_ops);
11190974658dSNicolas Dichtel 	goto out;
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds 
11221da177e4SLinus Torvalds static void __exit ipip_fini(void)
11231da177e4SLinus Torvalds {
11240974658dSNicolas Dichtel 	rtnl_link_unregister(&ipip_link_ops);
1125c0d56408SKazunori MIYAZAWA 	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
1126058bd4d2SJoe Perches 		pr_info("%s: can't deregister tunnel\n", __func__);
11271da177e4SLinus Torvalds 
112886de8a63SEric W. Biederman 	unregister_pernet_device(&ipip_net_ops);
11291da177e4SLinus Torvalds }
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds module_init(ipip_init);
11321da177e4SLinus Torvalds module_exit(ipip_fini);
11331da177e4SLinus Torvalds MODULE_LICENSE("GPL");
11348909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0");
1135