xref: /linux/net/ipv4/ipip.c (revision 64bc17811b72758753e2b64cd8f2a63812c61fe1)
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>
997c0f6ba6SLinus Torvalds #include <linux/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/init.h>
1071da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
10846f25dffSKris Katterjohn #include <linux/if_ether.h>
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds #include <net/sock.h>
1111da177e4SLinus Torvalds #include <net/ip.h>
1121da177e4SLinus Torvalds #include <net/icmp.h>
113c5441932SPravin B Shelar #include <net/ip_tunnels.h>
1141da177e4SLinus Torvalds #include <net/inet_ecn.h>
1151da177e4SLinus Torvalds #include <net/xfrm.h>
11610dc4c7bSPavel Emelyanov #include <net/net_namespace.h>
11710dc4c7bSPavel Emelyanov #include <net/netns/generic.h>
118cfc7381bSAlexei Starovoitov #include <net/dst_metadata.h>
1191da177e4SLinus Torvalds 
120eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
121eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
122eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
123eccc1bb8Sstephen hemminger 
124c7d03a00SAlexey Dobriyan static unsigned int ipip_net_id __read_mostly;
12510dc4c7bSPavel Emelyanov 
1263c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev);
1270974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly;
1281da177e4SLinus Torvalds 
129d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info)
1301da177e4SLinus Torvalds {
1311da177e4SLinus Torvalds 
132071f92d0SRami Rosen /* All the routers (except for Linux) return only
1331da177e4SLinus Torvalds    8 bytes of packet payload. It means, that precise relaying of
1341da177e4SLinus Torvalds    ICMP in the real Internet is absolutely infeasible.
1351da177e4SLinus Torvalds  */
136fd58156eSPravin B Shelar 	struct net *net = dev_net(skb->dev);
137fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
138b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
1391da177e4SLinus Torvalds 	struct ip_tunnel *t;
140d2acc347SHerbert Xu 	int err;
141fd58156eSPravin B Shelar 	const int type = icmp_hdr(skb)->type;
142fd58156eSPravin B Shelar 	const int code = icmp_hdr(skb)->code;
1431da177e4SLinus Torvalds 
144d2acc347SHerbert Xu 	err = -ENOENT;
145fd58156eSPravin B Shelar 	t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
146fd58156eSPravin B Shelar 			     iph->daddr, iph->saddr, 0);
14751456b29SIan Morris 	if (!t)
14836393395SDavid S. Miller 		goto out;
14936393395SDavid S. Miller 
15036393395SDavid S. Miller 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
15136393395SDavid S. Miller 		ipv4_update_pmtu(skb, dev_net(skb->dev), info,
1521b69e7e6SSimon Horman 				 t->parms.link, 0, iph->protocol, 0);
15336393395SDavid S. Miller 		err = 0;
15436393395SDavid S. Miller 		goto out;
15536393395SDavid S. Miller 	}
15636393395SDavid S. Miller 
15755be7a9cSDavid S. Miller 	if (type == ICMP_REDIRECT) {
1582346829eSDmitry Popov 		ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
1591b69e7e6SSimon Horman 			      iph->protocol, 0);
16055be7a9cSDavid S. Miller 		err = 0;
16155be7a9cSDavid S. Miller 		goto out;
16255be7a9cSDavid S. Miller 	}
16355be7a9cSDavid S. Miller 
16436393395SDavid S. Miller 	if (t->parms.iph.daddr == 0)
1651da177e4SLinus Torvalds 		goto out;
166d2acc347SHerbert Xu 
167d2acc347SHerbert Xu 	err = 0;
1681da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
1691da177e4SLinus Torvalds 		goto out;
1701da177e4SLinus Torvalds 
17126d94b46SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1721da177e4SLinus Torvalds 		t->err_count++;
1731da177e4SLinus Torvalds 	else
1741da177e4SLinus Torvalds 		t->err_count = 1;
1751da177e4SLinus Torvalds 	t->err_time = jiffies;
176b0558ef2Sstephen hemminger 
177fd58156eSPravin B Shelar out:
178d2acc347SHerbert Xu 	return err;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds 
1811b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = {
182fd58156eSPravin B Shelar 	/* no tunnel info required for ipip. */
183fd58156eSPravin B Shelar 	.proto = htons(ETH_P_IP),
184fd58156eSPravin B Shelar };
185fd58156eSPravin B Shelar 
1861b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
1871b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = {
1881b69e7e6SSimon Horman 	/* no tunnel info required for mplsip. */
1891b69e7e6SSimon Horman 	.proto = htons(ETH_P_MPLS_UC),
1901b69e7e6SSimon Horman };
1911b69e7e6SSimon Horman #endif
1921b69e7e6SSimon Horman 
1931b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
1941da177e4SLinus Torvalds {
195fd58156eSPravin B Shelar 	struct net *net = dev_net(skb->dev);
196fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
197cfc7381bSAlexei Starovoitov 	struct metadata_dst *tun_dst = NULL;
1981da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
1993d7b46cdSPravin B Shelar 	const struct iphdr *iph;
2001da177e4SLinus Torvalds 
2013d7b46cdSPravin B Shelar 	iph = ip_hdr(skb);
202fd58156eSPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
203fd58156eSPravin B Shelar 			iph->saddr, iph->daddr, 0);
204fd58156eSPravin B Shelar 	if (tunnel) {
2051b69e7e6SSimon Horman 		const struct tnl_ptk_info *tpi;
2061b69e7e6SSimon Horman 
2071b69e7e6SSimon Horman 		if (tunnel->parms.iph.protocol != ipproto &&
2081b69e7e6SSimon Horman 		    tunnel->parms.iph.protocol != 0)
2091b69e7e6SSimon Horman 			goto drop;
2101b69e7e6SSimon Horman 
211eccc1bb8Sstephen hemminger 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
212eccc1bb8Sstephen hemminger 			goto drop;
2131b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2141b69e7e6SSimon Horman 		if (ipproto == IPPROTO_MPLS)
2151b69e7e6SSimon Horman 			tpi = &mplsip_tpi;
2161b69e7e6SSimon Horman 		else
2171b69e7e6SSimon Horman #endif
2181b69e7e6SSimon Horman 			tpi = &ipip_tpi;
2191b69e7e6SSimon Horman 		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
220737e828bSLi Hongjun 			goto drop;
221cfc7381bSAlexei Starovoitov 		if (tunnel->collect_md) {
222cfc7381bSAlexei Starovoitov 			tun_dst = ip_tun_rx_dst(skb, 0, 0, 0);
223cfc7381bSAlexei Starovoitov 			if (!tun_dst)
224cfc7381bSAlexei Starovoitov 				return 0;
225cfc7381bSAlexei Starovoitov 		}
226cfc7381bSAlexei Starovoitov 		return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
2271da177e4SLinus Torvalds 	}
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	return -1;
230eccc1bb8Sstephen hemminger 
231eccc1bb8Sstephen hemminger drop:
232eccc1bb8Sstephen hemminger 	kfree_skb(skb);
233eccc1bb8Sstephen hemminger 	return 0;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
2361b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb)
2371b69e7e6SSimon Horman {
2381b69e7e6SSimon Horman 	return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
2391b69e7e6SSimon Horman }
2401b69e7e6SSimon Horman 
2411b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2421b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb)
2431b69e7e6SSimon Horman {
2441b69e7e6SSimon Horman 	return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
2451b69e7e6SSimon Horman }
2461b69e7e6SSimon Horman #endif
2471b69e7e6SSimon Horman 
2481da177e4SLinus Torvalds /*
2491da177e4SLinus Torvalds  *	This function assumes it is being called from dev_queue_xmit()
2501da177e4SLinus Torvalds  *	and that skb is filled properly by that function.
2511da177e4SLinus Torvalds  */
2521b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
2531b69e7e6SSimon Horman 				    struct net_device *dev)
2541da177e4SLinus Torvalds {
2552941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
256b71d1d42SEric Dumazet 	const struct iphdr  *tiph = &tunnel->parms.iph;
2571b69e7e6SSimon Horman 	u8 ipproto;
2581da177e4SLinus Torvalds 
2591b69e7e6SSimon Horman 	switch (skb->protocol) {
2601b69e7e6SSimon Horman 	case htons(ETH_P_IP):
2611b69e7e6SSimon Horman 		ipproto = IPPROTO_IPIP;
2621b69e7e6SSimon Horman 		break;
2631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2641b69e7e6SSimon Horman 	case htons(ETH_P_MPLS_UC):
2651b69e7e6SSimon Horman 		ipproto = IPPROTO_MPLS;
2661b69e7e6SSimon Horman 		break;
2671b69e7e6SSimon Horman #endif
2681b69e7e6SSimon Horman 	default:
2691b69e7e6SSimon Horman 		goto tx_error;
2701b69e7e6SSimon Horman 	}
2711b69e7e6SSimon Horman 
2721b69e7e6SSimon Horman 	if (tiph->protocol != ipproto && tiph->protocol != 0)
2731da177e4SLinus Torvalds 		goto tx_error;
274cef401deSEric Dumazet 
2757e13318dSTom Herbert 	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
276aed069dfSAlexander Duyck 		goto tx_error;
2774f3ed920SPravin B Shelar 
2781b69e7e6SSimon Horman 	skb_set_inner_ipproto(skb, ipproto);
279077c5a09STom Herbert 
280cfc7381bSAlexei Starovoitov 	if (tunnel->collect_md)
281cfc7381bSAlexei Starovoitov 		ip_md_tunnel_xmit(skb, dev, ipproto);
282cfc7381bSAlexei Starovoitov 	else
2831b69e7e6SSimon Horman 		ip_tunnel_xmit(skb, dev, tiph, ipproto);
2846ed10654SPatrick McHardy 	return NETDEV_TX_OK;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds tx_error:
2873acfa1e7SEric Dumazet 	kfree_skb(skb);
288aed069dfSAlexander Duyck 
289cb32f511SEric Dumazet 	dev->stats.tx_errors++;
2906ed10654SPatrick McHardy 	return NETDEV_TX_OK;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
2931b69e7e6SSimon Horman static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
2941b69e7e6SSimon Horman {
2951b69e7e6SSimon Horman 	switch (ipproto) {
2961b69e7e6SSimon Horman 	case 0:
2971b69e7e6SSimon Horman 	case IPPROTO_IPIP:
2981b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2991b69e7e6SSimon Horman 	case IPPROTO_MPLS:
3001b69e7e6SSimon Horman #endif
3011b69e7e6SSimon Horman 		return true;
3021b69e7e6SSimon Horman 	}
3031b69e7e6SSimon Horman 
3041b69e7e6SSimon Horman 	return false;
3051b69e7e6SSimon Horman }
3061b69e7e6SSimon Horman 
3071da177e4SLinus Torvalds static int
3081da177e4SLinus Torvalds ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3091da177e4SLinus Torvalds {
3101da177e4SLinus Torvalds 	int err = 0;
3111da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
314fd58156eSPravin B Shelar 		return -EFAULT;
3151da177e4SLinus Torvalds 
3163b7b514fSCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
3171b69e7e6SSimon Horman 		if (p.iph.version != 4 ||
3181b69e7e6SSimon Horman 		    !ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) ||
3191da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
320fd58156eSPravin B Shelar 			return -EINVAL;
3213b7b514fSCong Wang 	}
3223b7b514fSCong Wang 
323252a8fbeSEric Dumazet 	p.i_key = p.o_key = 0;
324252a8fbeSEric Dumazet 	p.i_flags = p.o_flags = 0;
325fd58156eSPravin B Shelar 	err = ip_tunnel_ioctl(dev, &p, cmd);
326fd58156eSPravin B Shelar 	if (err)
3271da177e4SLinus Torvalds 		return err;
3281da177e4SLinus Torvalds 
329fd58156eSPravin B Shelar 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
330fd58156eSPravin B Shelar 		return -EFAULT;
331fd58156eSPravin B Shelar 
3321da177e4SLinus Torvalds 	return 0;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
33523a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = {
336fd58156eSPravin B Shelar 	.ndo_init       = ipip_tunnel_init,
337fd58156eSPravin B Shelar 	.ndo_uninit     = ip_tunnel_uninit,
33823a12b14SStephen Hemminger 	.ndo_start_xmit	= ipip_tunnel_xmit,
33923a12b14SStephen Hemminger 	.ndo_do_ioctl	= ipip_tunnel_ioctl,
340fd58156eSPravin B Shelar 	.ndo_change_mtu = ip_tunnel_change_mtu,
341fd58156eSPravin B Shelar 	.ndo_get_stats64 = ip_tunnel_get_stats64,
3421e99584bSNicolas Dichtel 	.ndo_get_iflink = ip_tunnel_get_iflink,
34323a12b14SStephen Hemminger };
34423a12b14SStephen Hemminger 
345c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG |		\
346c3b89fbbSEric Dumazet 		       NETIF_F_FRAGLIST |	\
347c3b89fbbSEric Dumazet 		       NETIF_F_HIGHDMA |	\
348cb32f511SEric Dumazet 		       NETIF_F_GSO_SOFTWARE |	\
349c3b89fbbSEric Dumazet 		       NETIF_F_HW_CSUM)
350c3b89fbbSEric Dumazet 
3511da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev)
3521da177e4SLinus Torvalds {
35323a12b14SStephen Hemminger 	dev->netdev_ops		= &ipip_netdev_ops;
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	dev->type		= ARPHRD_TUNNEL;
3561da177e4SLinus Torvalds 	dev->flags		= IFF_NOARP;
3571da177e4SLinus Torvalds 	dev->addr_len		= 4;
358153f0943SEric Dumazet 	dev->features		|= NETIF_F_LLTX;
35902875878SEric Dumazet 	netif_keep_dst(dev);
360c3b89fbbSEric Dumazet 
361c3b89fbbSEric Dumazet 	dev->features		|= IPIP_FEATURES;
362c3b89fbbSEric Dumazet 	dev->hw_features	|= IPIP_FEATURES;
363fd58156eSPravin B Shelar 	ip_tunnel_setup(dev, ipip_net_id);
3641da177e4SLinus Torvalds }
3651da177e4SLinus Torvalds 
3663c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev)
3671da177e4SLinus Torvalds {
36823a12b14SStephen Hemminger 	struct ip_tunnel *tunnel = netdev_priv(dev);
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
3711da177e4SLinus Torvalds 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
3721da177e4SLinus Torvalds 
373473ab820STom Herbert 	tunnel->tun_hlen = 0;
374473ab820STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
375fd58156eSPravin B Shelar 	return ip_tunnel_init(dev);
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds 
378a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
379a8b8a889SMatthias Schiffer 				struct netlink_ext_ack *extack)
3801b69e7e6SSimon Horman {
3811b69e7e6SSimon Horman 	u8 proto;
3821b69e7e6SSimon Horman 
3831b69e7e6SSimon Horman 	if (!data || !data[IFLA_IPTUN_PROTO])
3841b69e7e6SSimon Horman 		return 0;
3851b69e7e6SSimon Horman 
3861b69e7e6SSimon Horman 	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
3871b69e7e6SSimon Horman 	if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
3881b69e7e6SSimon Horman 		return -EINVAL;
3891b69e7e6SSimon Horman 
3901b69e7e6SSimon Horman 	return 0;
3911b69e7e6SSimon Horman }
3921b69e7e6SSimon Horman 
393be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[],
3949830ad4cSCraig Gallek 			       struct ip_tunnel_parm *parms, bool *collect_md,
3959830ad4cSCraig Gallek 			       __u32 *fwmark)
396be42da0eSNicolas Dichtel {
397be42da0eSNicolas Dichtel 	memset(parms, 0, sizeof(*parms));
398be42da0eSNicolas Dichtel 
399be42da0eSNicolas Dichtel 	parms->iph.version = 4;
400be42da0eSNicolas Dichtel 	parms->iph.protocol = IPPROTO_IPIP;
401be42da0eSNicolas Dichtel 	parms->iph.ihl = 5;
402cfc7381bSAlexei Starovoitov 	*collect_md = false;
403be42da0eSNicolas Dichtel 
404be42da0eSNicolas Dichtel 	if (!data)
405be42da0eSNicolas Dichtel 		return;
406be42da0eSNicolas Dichtel 
407be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_LINK])
408be42da0eSNicolas Dichtel 		parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
409be42da0eSNicolas Dichtel 
410be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_LOCAL])
41167b61f6cSJiri Benc 		parms->iph.saddr = nla_get_in_addr(data[IFLA_IPTUN_LOCAL]);
412be42da0eSNicolas Dichtel 
413be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_REMOTE])
41467b61f6cSJiri Benc 		parms->iph.daddr = nla_get_in_addr(data[IFLA_IPTUN_REMOTE]);
415be42da0eSNicolas Dichtel 
416be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_TTL]) {
417be42da0eSNicolas Dichtel 		parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
418be42da0eSNicolas Dichtel 		if (parms->iph.ttl)
419be42da0eSNicolas Dichtel 			parms->iph.frag_off = htons(IP_DF);
420be42da0eSNicolas Dichtel 	}
421be42da0eSNicolas Dichtel 
422be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_TOS])
423be42da0eSNicolas Dichtel 		parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
424be42da0eSNicolas Dichtel 
4251b69e7e6SSimon Horman 	if (data[IFLA_IPTUN_PROTO])
4261b69e7e6SSimon Horman 		parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
4271b69e7e6SSimon Horman 
428be42da0eSNicolas Dichtel 	if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
429be42da0eSNicolas Dichtel 		parms->iph.frag_off = htons(IP_DF);
430cfc7381bSAlexei Starovoitov 
431cfc7381bSAlexei Starovoitov 	if (data[IFLA_IPTUN_COLLECT_METADATA])
432cfc7381bSAlexei Starovoitov 		*collect_md = true;
4339830ad4cSCraig Gallek 
4349830ad4cSCraig Gallek 	if (data[IFLA_IPTUN_FWMARK])
4359830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
436be42da0eSNicolas Dichtel }
437be42da0eSNicolas Dichtel 
438473ab820STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
439473ab820STom Herbert static bool ipip_netlink_encap_parms(struct nlattr *data[],
440473ab820STom Herbert 				     struct ip_tunnel_encap *ipencap)
441473ab820STom Herbert {
442473ab820STom Herbert 	bool ret = false;
443473ab820STom Herbert 
444473ab820STom Herbert 	memset(ipencap, 0, sizeof(*ipencap));
445473ab820STom Herbert 
446473ab820STom Herbert 	if (!data)
447473ab820STom Herbert 		return ret;
448473ab820STom Herbert 
449473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_TYPE]) {
450473ab820STom Herbert 		ret = true;
451473ab820STom Herbert 		ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
452473ab820STom Herbert 	}
453473ab820STom Herbert 
454473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
455473ab820STom Herbert 		ret = true;
456473ab820STom Herbert 		ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
457473ab820STom Herbert 	}
458473ab820STom Herbert 
459473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_SPORT]) {
460473ab820STom Herbert 		ret = true;
4613e97fa70SSabrina Dubroca 		ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]);
462473ab820STom Herbert 	}
463473ab820STom Herbert 
464473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_DPORT]) {
465473ab820STom Herbert 		ret = true;
4663e97fa70SSabrina Dubroca 		ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]);
467473ab820STom Herbert 	}
468473ab820STom Herbert 
469473ab820STom Herbert 	return ret;
470473ab820STom Herbert }
471473ab820STom Herbert 
472be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev,
4737a3f4a18SMatthias Schiffer 			struct nlattr *tb[], struct nlattr *data[],
4747a3f4a18SMatthias Schiffer 			struct netlink_ext_ack *extack)
475be42da0eSNicolas Dichtel {
476cfc7381bSAlexei Starovoitov 	struct ip_tunnel *t = netdev_priv(dev);
477fd58156eSPravin B Shelar 	struct ip_tunnel_parm p;
478473ab820STom Herbert 	struct ip_tunnel_encap ipencap;
4799830ad4cSCraig Gallek 	__u32 fwmark = 0;
480473ab820STom Herbert 
481473ab820STom Herbert 	if (ipip_netlink_encap_parms(data, &ipencap)) {
482473ab820STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
483473ab820STom Herbert 
484473ab820STom Herbert 		if (err < 0)
485473ab820STom Herbert 			return err;
486473ab820STom Herbert 	}
487be42da0eSNicolas Dichtel 
4889830ad4cSCraig Gallek 	ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
4899830ad4cSCraig Gallek 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
490be42da0eSNicolas Dichtel }
491be42da0eSNicolas Dichtel 
492be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
493ad744b22SMatthias Schiffer 			   struct nlattr *data[],
494ad744b22SMatthias Schiffer 			   struct netlink_ext_ack *extack)
495be42da0eSNicolas Dichtel {
4969830ad4cSCraig Gallek 	struct ip_tunnel *t = netdev_priv(dev);
497be42da0eSNicolas Dichtel 	struct ip_tunnel_parm p;
498473ab820STom Herbert 	struct ip_tunnel_encap ipencap;
499cfc7381bSAlexei Starovoitov 	bool collect_md;
5009830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
501473ab820STom Herbert 
502473ab820STom Herbert 	if (ipip_netlink_encap_parms(data, &ipencap)) {
503473ab820STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
504473ab820STom Herbert 
505473ab820STom Herbert 		if (err < 0)
506473ab820STom Herbert 			return err;
507473ab820STom Herbert 	}
508be42da0eSNicolas Dichtel 
5099830ad4cSCraig Gallek 	ipip_netlink_parms(data, &p, &collect_md, &fwmark);
510cfc7381bSAlexei Starovoitov 	if (collect_md)
511cfc7381bSAlexei Starovoitov 		return -EINVAL;
512be42da0eSNicolas Dichtel 
513be42da0eSNicolas Dichtel 	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
514be42da0eSNicolas Dichtel 	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
515be42da0eSNicolas Dichtel 		return -EINVAL;
516be42da0eSNicolas Dichtel 
5179830ad4cSCraig Gallek 	return ip_tunnel_changelink(dev, tb, &p, fwmark);
518be42da0eSNicolas Dichtel }
519be42da0eSNicolas Dichtel 
5200974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev)
5210974658dSNicolas Dichtel {
5220974658dSNicolas Dichtel 	return
5230974658dSNicolas Dichtel 		/* IFLA_IPTUN_LINK */
5240974658dSNicolas Dichtel 		nla_total_size(4) +
5250974658dSNicolas Dichtel 		/* IFLA_IPTUN_LOCAL */
5260974658dSNicolas Dichtel 		nla_total_size(4) +
5270974658dSNicolas Dichtel 		/* IFLA_IPTUN_REMOTE */
5280974658dSNicolas Dichtel 		nla_total_size(4) +
5290974658dSNicolas Dichtel 		/* IFLA_IPTUN_TTL */
5300974658dSNicolas Dichtel 		nla_total_size(1) +
5310974658dSNicolas Dichtel 		/* IFLA_IPTUN_TOS */
5320974658dSNicolas Dichtel 		nla_total_size(1) +
5331b69e7e6SSimon Horman 		/* IFLA_IPTUN_PROTO */
5341b69e7e6SSimon Horman 		nla_total_size(1) +
535befe2aa1SNicolas Dichtel 		/* IFLA_IPTUN_PMTUDISC */
536befe2aa1SNicolas Dichtel 		nla_total_size(1) +
537473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_TYPE */
538473ab820STom Herbert 		nla_total_size(2) +
539473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_FLAGS */
540473ab820STom Herbert 		nla_total_size(2) +
541473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_SPORT */
542473ab820STom Herbert 		nla_total_size(2) +
543473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_DPORT */
544473ab820STom Herbert 		nla_total_size(2) +
545cfc7381bSAlexei Starovoitov 		/* IFLA_IPTUN_COLLECT_METADATA */
546cfc7381bSAlexei Starovoitov 		nla_total_size(0) +
5479830ad4cSCraig Gallek 		/* IFLA_IPTUN_FWMARK */
5489830ad4cSCraig Gallek 		nla_total_size(4) +
5490974658dSNicolas Dichtel 		0;
5500974658dSNicolas Dichtel }
5510974658dSNicolas Dichtel 
5520974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
5530974658dSNicolas Dichtel {
5540974658dSNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
5550974658dSNicolas Dichtel 	struct ip_tunnel_parm *parm = &tunnel->parms;
5560974658dSNicolas Dichtel 
5570974658dSNicolas Dichtel 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
558930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
559930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
5600974658dSNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
561befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
5621b69e7e6SSimon Horman 	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
563befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
5649830ad4cSCraig Gallek 		       !!(parm->iph.frag_off & htons(IP_DF))) ||
5659830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
5660974658dSNicolas Dichtel 		goto nla_put_failure;
567473ab820STom Herbert 
568473ab820STom Herbert 	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
569473ab820STom Herbert 			tunnel->encap.type) ||
5703e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
571473ab820STom Herbert 			 tunnel->encap.sport) ||
5723e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
573473ab820STom Herbert 			 tunnel->encap.dport) ||
574473ab820STom Herbert 	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
575e1b2cb65STom Herbert 			tunnel->encap.flags))
576473ab820STom Herbert 		goto nla_put_failure;
577473ab820STom Herbert 
578cfc7381bSAlexei Starovoitov 	if (tunnel->collect_md)
579cfc7381bSAlexei Starovoitov 		if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
580cfc7381bSAlexei Starovoitov 			goto nla_put_failure;
5810974658dSNicolas Dichtel 	return 0;
5820974658dSNicolas Dichtel 
5830974658dSNicolas Dichtel nla_put_failure:
5840974658dSNicolas Dichtel 	return -EMSGSIZE;
5850974658dSNicolas Dichtel }
5860974658dSNicolas Dichtel 
587be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
588be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
589be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
590be42da0eSNicolas Dichtel 	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
591be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
592be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
5931b69e7e6SSimon Horman 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
594be42da0eSNicolas Dichtel 	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
595473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
596473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
597473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
598473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
599cfc7381bSAlexei Starovoitov 	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
6009830ad4cSCraig Gallek 	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
601be42da0eSNicolas Dichtel };
602be42da0eSNicolas Dichtel 
6030974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = {
6040974658dSNicolas Dichtel 	.kind		= "ipip",
6050974658dSNicolas Dichtel 	.maxtype	= IFLA_IPTUN_MAX,
606be42da0eSNicolas Dichtel 	.policy		= ipip_policy,
6070974658dSNicolas Dichtel 	.priv_size	= sizeof(struct ip_tunnel),
608be42da0eSNicolas Dichtel 	.setup		= ipip_tunnel_setup,
6091b69e7e6SSimon Horman 	.validate	= ipip_tunnel_validate,
610be42da0eSNicolas Dichtel 	.newlink	= ipip_newlink,
611be42da0eSNicolas Dichtel 	.changelink	= ipip_changelink,
612fd58156eSPravin B Shelar 	.dellink	= ip_tunnel_dellink,
6130974658dSNicolas Dichtel 	.get_size	= ipip_get_size,
6140974658dSNicolas Dichtel 	.fill_info	= ipip_fill_info,
6151728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
6160974658dSNicolas Dichtel };
6170974658dSNicolas Dichtel 
6186dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = {
6191da177e4SLinus Torvalds 	.handler	=	ipip_rcv,
6201da177e4SLinus Torvalds 	.err_handler	=	ipip_err,
621d2acc347SHerbert Xu 	.priority	=	1,
6221da177e4SLinus Torvalds };
6231da177e4SLinus Torvalds 
6241b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6251b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = {
6261b69e7e6SSimon Horman 	.handler	=	mplsip_rcv,
6271b69e7e6SSimon Horman 	.err_handler	=	ipip_err,
6281b69e7e6SSimon Horman 	.priority	=	1,
6291b69e7e6SSimon Horman };
6301b69e7e6SSimon Horman #endif
6311b69e7e6SSimon Horman 
6322c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net)
63310dc4c7bSPavel Emelyanov {
634fd58156eSPravin B Shelar 	return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
63510dc4c7bSPavel Emelyanov }
63610dc4c7bSPavel Emelyanov 
637*64bc1781SEric Dumazet static void __net_exit ipip_exit_batch_net(struct list_head *list_net)
63810dc4c7bSPavel Emelyanov {
639*64bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops);
64010dc4c7bSPavel Emelyanov }
64110dc4c7bSPavel Emelyanov 
64210dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = {
64310dc4c7bSPavel Emelyanov 	.init = ipip_init_net,
644*64bc1781SEric Dumazet 	.exit_batch = ipip_exit_batch_net,
64586de8a63SEric W. Biederman 	.id   = &ipip_net_id,
646fd58156eSPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
64710dc4c7bSPavel Emelyanov };
64810dc4c7bSPavel Emelyanov 
6491da177e4SLinus Torvalds static int __init ipip_init(void)
6501da177e4SLinus Torvalds {
6511da177e4SLinus Torvalds 	int err;
6521da177e4SLinus Torvalds 
6531b69e7e6SSimon Horman 	pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
6541da177e4SLinus Torvalds 
65586de8a63SEric W. Biederman 	err = register_pernet_device(&ipip_net_ops);
656d5aa407fSAlexey Dobriyan 	if (err < 0)
657d5aa407fSAlexey Dobriyan 		return err;
658d5aa407fSAlexey Dobriyan 	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
659d5aa407fSAlexey Dobriyan 	if (err < 0) {
660058bd4d2SJoe Perches 		pr_info("%s: can't register tunnel\n", __func__);
6611b69e7e6SSimon Horman 		goto xfrm_tunnel_ipip_failed;
662d5aa407fSAlexey Dobriyan 	}
6631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6641b69e7e6SSimon Horman 	err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
6651b69e7e6SSimon Horman 	if (err < 0) {
6661b69e7e6SSimon Horman 		pr_info("%s: can't register tunnel\n", __func__);
6671b69e7e6SSimon Horman 		goto xfrm_tunnel_mplsip_failed;
6681b69e7e6SSimon Horman 	}
6691b69e7e6SSimon Horman #endif
6700974658dSNicolas Dichtel 	err = rtnl_link_register(&ipip_link_ops);
6710974658dSNicolas Dichtel 	if (err < 0)
6720974658dSNicolas Dichtel 		goto rtnl_link_failed;
6730974658dSNicolas Dichtel 
6740974658dSNicolas Dichtel out:
675b9855c54SPavel Emelyanov 	return err;
6760974658dSNicolas Dichtel 
6770974658dSNicolas Dichtel rtnl_link_failed:
6781b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6791b69e7e6SSimon Horman 	xfrm4_tunnel_deregister(&mplsip_handler, AF_INET);
6801b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed:
6811b69e7e6SSimon Horman 
6821b69e7e6SSimon Horman #endif
6830974658dSNicolas Dichtel 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
6841b69e7e6SSimon Horman xfrm_tunnel_ipip_failed:
6850974658dSNicolas Dichtel 	unregister_pernet_device(&ipip_net_ops);
6860974658dSNicolas Dichtel 	goto out;
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds static void __exit ipip_fini(void)
6901da177e4SLinus Torvalds {
6910974658dSNicolas Dichtel 	rtnl_link_unregister(&ipip_link_ops);
692c0d56408SKazunori MIYAZAWA 	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
693058bd4d2SJoe Perches 		pr_info("%s: can't deregister tunnel\n", __func__);
6941b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6951b69e7e6SSimon Horman 	if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
6961b69e7e6SSimon Horman 		pr_info("%s: can't deregister tunnel\n", __func__);
6971b69e7e6SSimon Horman #endif
69886de8a63SEric W. Biederman 	unregister_pernet_device(&ipip_net_ops);
6991da177e4SLinus Torvalds }
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds module_init(ipip_init);
7021da177e4SLinus Torvalds module_exit(ipip_fini);
7031da177e4SLinus Torvalds MODULE_LICENSE("GPL");
704f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip");
7058909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0");
706