xref: /linux/net/ipv4/ipip.c (revision f3594f0a7ea36661d7fd942facd7f31a64245f1a)
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 {
131071f92d0SRami Rosen 	/* All the routers (except for Linux) return only
132*f3594f0aSXin Long 	 * 8 bytes of packet payload. It means, that precise relaying of
133*f3594f0aSXin Long 	 * ICMP in the real Internet is absolutely infeasible.
1341da177e4SLinus Torvalds 	 */
135fd58156eSPravin B Shelar 	struct net *net = dev_net(skb->dev);
136fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
137b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
138fd58156eSPravin B Shelar 	const int type = icmp_hdr(skb)->type;
139fd58156eSPravin B Shelar 	const int code = icmp_hdr(skb)->code;
140*f3594f0aSXin Long 	struct ip_tunnel *t;
141*f3594f0aSXin Long 	int err = 0;
1421da177e4SLinus Torvalds 
143*f3594f0aSXin Long 	switch (type) {
144*f3594f0aSXin Long 	case ICMP_DEST_UNREACH:
145*f3594f0aSXin Long 		switch (code) {
146*f3594f0aSXin Long 		case ICMP_SR_FAILED:
147*f3594f0aSXin Long 			/* Impossible event. */
148*f3594f0aSXin Long 			goto out;
149*f3594f0aSXin Long 		default:
150*f3594f0aSXin Long 			/* All others are translated to HOST_UNREACH.
151*f3594f0aSXin Long 			 * rfc2003 contains "deep thoughts" about NET_UNREACH,
152*f3594f0aSXin Long 			 * I believe they are just ether pollution. --ANK
153*f3594f0aSXin Long 			 */
154*f3594f0aSXin Long 			break;
155*f3594f0aSXin Long 		}
156*f3594f0aSXin Long 		break;
157*f3594f0aSXin Long 
158*f3594f0aSXin Long 	case ICMP_TIME_EXCEEDED:
159*f3594f0aSXin Long 		if (code != ICMP_EXC_TTL)
160*f3594f0aSXin Long 			goto out;
161*f3594f0aSXin Long 		break;
162*f3594f0aSXin Long 
163*f3594f0aSXin Long 	case ICMP_REDIRECT:
164*f3594f0aSXin Long 		break;
165*f3594f0aSXin Long 
166*f3594f0aSXin Long 	default:
167*f3594f0aSXin Long 		goto out;
168*f3594f0aSXin Long 	}
169*f3594f0aSXin Long 
170fd58156eSPravin B Shelar 	t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
171fd58156eSPravin B Shelar 			     iph->daddr, iph->saddr, 0);
172*f3594f0aSXin Long 	if (!t) {
173*f3594f0aSXin Long 		err = -ENOENT;
17436393395SDavid S. Miller 		goto out;
175*f3594f0aSXin Long 	}
17636393395SDavid S. Miller 
17736393395SDavid S. Miller 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
178*f3594f0aSXin Long 		ipv4_update_pmtu(skb, net, info, t->parms.link, 0,
179*f3594f0aSXin Long 				 iph->protocol, 0);
18036393395SDavid S. Miller 		goto out;
18136393395SDavid S. Miller 	}
18236393395SDavid S. Miller 
18355be7a9cSDavid S. Miller 	if (type == ICMP_REDIRECT) {
184*f3594f0aSXin Long 		ipv4_redirect(skb, net, t->parms.link, 0, iph->protocol, 0);
18555be7a9cSDavid S. Miller 		goto out;
18655be7a9cSDavid S. Miller 	}
18755be7a9cSDavid S. Miller 
188*f3594f0aSXin Long 	if (t->parms.iph.daddr == 0) {
189*f3594f0aSXin Long 		err = -ENOENT;
1901da177e4SLinus Torvalds 		goto out;
191*f3594f0aSXin Long 	}
192d2acc347SHerbert Xu 
1931da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
1941da177e4SLinus Torvalds 		goto out;
1951da177e4SLinus Torvalds 
19626d94b46SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1971da177e4SLinus Torvalds 		t->err_count++;
1981da177e4SLinus Torvalds 	else
1991da177e4SLinus Torvalds 		t->err_count = 1;
2001da177e4SLinus Torvalds 	t->err_time = jiffies;
201b0558ef2Sstephen hemminger 
202fd58156eSPravin B Shelar out:
203d2acc347SHerbert Xu 	return err;
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds 
2061b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = {
207fd58156eSPravin B Shelar 	/* no tunnel info required for ipip. */
208fd58156eSPravin B Shelar 	.proto = htons(ETH_P_IP),
209fd58156eSPravin B Shelar };
210fd58156eSPravin B Shelar 
2111b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2121b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = {
2131b69e7e6SSimon Horman 	/* no tunnel info required for mplsip. */
2141b69e7e6SSimon Horman 	.proto = htons(ETH_P_MPLS_UC),
2151b69e7e6SSimon Horman };
2161b69e7e6SSimon Horman #endif
2171b69e7e6SSimon Horman 
2181b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
2191da177e4SLinus Torvalds {
220fd58156eSPravin B Shelar 	struct net *net = dev_net(skb->dev);
221fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
222cfc7381bSAlexei Starovoitov 	struct metadata_dst *tun_dst = NULL;
2231da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
2243d7b46cdSPravin B Shelar 	const struct iphdr *iph;
2251da177e4SLinus Torvalds 
2263d7b46cdSPravin B Shelar 	iph = ip_hdr(skb);
227fd58156eSPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
228fd58156eSPravin B Shelar 			iph->saddr, iph->daddr, 0);
229fd58156eSPravin B Shelar 	if (tunnel) {
2301b69e7e6SSimon Horman 		const struct tnl_ptk_info *tpi;
2311b69e7e6SSimon Horman 
2321b69e7e6SSimon Horman 		if (tunnel->parms.iph.protocol != ipproto &&
2331b69e7e6SSimon Horman 		    tunnel->parms.iph.protocol != 0)
2341b69e7e6SSimon Horman 			goto drop;
2351b69e7e6SSimon Horman 
236eccc1bb8Sstephen hemminger 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
237eccc1bb8Sstephen hemminger 			goto drop;
2381b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2391b69e7e6SSimon Horman 		if (ipproto == IPPROTO_MPLS)
2401b69e7e6SSimon Horman 			tpi = &mplsip_tpi;
2411b69e7e6SSimon Horman 		else
2421b69e7e6SSimon Horman #endif
2431b69e7e6SSimon Horman 			tpi = &ipip_tpi;
2441b69e7e6SSimon Horman 		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
245737e828bSLi Hongjun 			goto drop;
246cfc7381bSAlexei Starovoitov 		if (tunnel->collect_md) {
247cfc7381bSAlexei Starovoitov 			tun_dst = ip_tun_rx_dst(skb, 0, 0, 0);
248cfc7381bSAlexei Starovoitov 			if (!tun_dst)
249cfc7381bSAlexei Starovoitov 				return 0;
250cfc7381bSAlexei Starovoitov 		}
251cfc7381bSAlexei Starovoitov 		return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
2521da177e4SLinus Torvalds 	}
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	return -1;
255eccc1bb8Sstephen hemminger 
256eccc1bb8Sstephen hemminger drop:
257eccc1bb8Sstephen hemminger 	kfree_skb(skb);
258eccc1bb8Sstephen hemminger 	return 0;
2591da177e4SLinus Torvalds }
2601da177e4SLinus Torvalds 
2611b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb)
2621b69e7e6SSimon Horman {
2631b69e7e6SSimon Horman 	return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
2641b69e7e6SSimon Horman }
2651b69e7e6SSimon Horman 
2661b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2671b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb)
2681b69e7e6SSimon Horman {
2691b69e7e6SSimon Horman 	return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
2701b69e7e6SSimon Horman }
2711b69e7e6SSimon Horman #endif
2721b69e7e6SSimon Horman 
2731da177e4SLinus Torvalds /*
2741da177e4SLinus Torvalds  *	This function assumes it is being called from dev_queue_xmit()
2751da177e4SLinus Torvalds  *	and that skb is filled properly by that function.
2761da177e4SLinus Torvalds  */
2771b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
2781b69e7e6SSimon Horman 				    struct net_device *dev)
2791da177e4SLinus Torvalds {
2802941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
281b71d1d42SEric Dumazet 	const struct iphdr  *tiph = &tunnel->parms.iph;
2821b69e7e6SSimon Horman 	u8 ipproto;
2831da177e4SLinus Torvalds 
2841b69e7e6SSimon Horman 	switch (skb->protocol) {
2851b69e7e6SSimon Horman 	case htons(ETH_P_IP):
2861b69e7e6SSimon Horman 		ipproto = IPPROTO_IPIP;
2871b69e7e6SSimon Horman 		break;
2881b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2891b69e7e6SSimon Horman 	case htons(ETH_P_MPLS_UC):
2901b69e7e6SSimon Horman 		ipproto = IPPROTO_MPLS;
2911b69e7e6SSimon Horman 		break;
2921b69e7e6SSimon Horman #endif
2931b69e7e6SSimon Horman 	default:
2941b69e7e6SSimon Horman 		goto tx_error;
2951b69e7e6SSimon Horman 	}
2961b69e7e6SSimon Horman 
2971b69e7e6SSimon Horman 	if (tiph->protocol != ipproto && tiph->protocol != 0)
2981da177e4SLinus Torvalds 		goto tx_error;
299cef401deSEric Dumazet 
3007e13318dSTom Herbert 	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
301aed069dfSAlexander Duyck 		goto tx_error;
3024f3ed920SPravin B Shelar 
3031b69e7e6SSimon Horman 	skb_set_inner_ipproto(skb, ipproto);
304077c5a09STom Herbert 
305cfc7381bSAlexei Starovoitov 	if (tunnel->collect_md)
306cfc7381bSAlexei Starovoitov 		ip_md_tunnel_xmit(skb, dev, ipproto);
307cfc7381bSAlexei Starovoitov 	else
3081b69e7e6SSimon Horman 		ip_tunnel_xmit(skb, dev, tiph, ipproto);
3096ed10654SPatrick McHardy 	return NETDEV_TX_OK;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds tx_error:
3123acfa1e7SEric Dumazet 	kfree_skb(skb);
313aed069dfSAlexander Duyck 
314cb32f511SEric Dumazet 	dev->stats.tx_errors++;
3156ed10654SPatrick McHardy 	return NETDEV_TX_OK;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds 
3181b69e7e6SSimon Horman static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
3191b69e7e6SSimon Horman {
3201b69e7e6SSimon Horman 	switch (ipproto) {
3211b69e7e6SSimon Horman 	case 0:
3221b69e7e6SSimon Horman 	case IPPROTO_IPIP:
3231b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
3241b69e7e6SSimon Horman 	case IPPROTO_MPLS:
3251b69e7e6SSimon Horman #endif
3261b69e7e6SSimon Horman 		return true;
3271b69e7e6SSimon Horman 	}
3281b69e7e6SSimon Horman 
3291b69e7e6SSimon Horman 	return false;
3301b69e7e6SSimon Horman }
3311b69e7e6SSimon Horman 
3321da177e4SLinus Torvalds static int
3331da177e4SLinus Torvalds ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds 	int err = 0;
3361da177e4SLinus Torvalds 	struct ip_tunnel_parm p;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
339fd58156eSPravin B Shelar 		return -EFAULT;
3401da177e4SLinus Torvalds 
3413b7b514fSCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
3421b69e7e6SSimon Horman 		if (p.iph.version != 4 ||
3431b69e7e6SSimon Horman 		    !ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) ||
3441da177e4SLinus Torvalds 		    p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
345fd58156eSPravin B Shelar 			return -EINVAL;
3463b7b514fSCong Wang 	}
3473b7b514fSCong Wang 
348252a8fbeSEric Dumazet 	p.i_key = p.o_key = 0;
349252a8fbeSEric Dumazet 	p.i_flags = p.o_flags = 0;
350fd58156eSPravin B Shelar 	err = ip_tunnel_ioctl(dev, &p, cmd);
351fd58156eSPravin B Shelar 	if (err)
3521da177e4SLinus Torvalds 		return err;
3531da177e4SLinus Torvalds 
354fd58156eSPravin B Shelar 	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
355fd58156eSPravin B Shelar 		return -EFAULT;
356fd58156eSPravin B Shelar 
3571da177e4SLinus Torvalds 	return 0;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
36023a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = {
361fd58156eSPravin B Shelar 	.ndo_init       = ipip_tunnel_init,
362fd58156eSPravin B Shelar 	.ndo_uninit     = ip_tunnel_uninit,
36323a12b14SStephen Hemminger 	.ndo_start_xmit	= ipip_tunnel_xmit,
36423a12b14SStephen Hemminger 	.ndo_do_ioctl	= ipip_tunnel_ioctl,
365fd58156eSPravin B Shelar 	.ndo_change_mtu = ip_tunnel_change_mtu,
366fd58156eSPravin B Shelar 	.ndo_get_stats64 = ip_tunnel_get_stats64,
3671e99584bSNicolas Dichtel 	.ndo_get_iflink = ip_tunnel_get_iflink,
36823a12b14SStephen Hemminger };
36923a12b14SStephen Hemminger 
370c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG |		\
371c3b89fbbSEric Dumazet 		       NETIF_F_FRAGLIST |	\
372c3b89fbbSEric Dumazet 		       NETIF_F_HIGHDMA |	\
373cb32f511SEric Dumazet 		       NETIF_F_GSO_SOFTWARE |	\
374c3b89fbbSEric Dumazet 		       NETIF_F_HW_CSUM)
375c3b89fbbSEric Dumazet 
3761da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev)
3771da177e4SLinus Torvalds {
37823a12b14SStephen Hemminger 	dev->netdev_ops		= &ipip_netdev_ops;
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	dev->type		= ARPHRD_TUNNEL;
3811da177e4SLinus Torvalds 	dev->flags		= IFF_NOARP;
3821da177e4SLinus Torvalds 	dev->addr_len		= 4;
383153f0943SEric Dumazet 	dev->features		|= NETIF_F_LLTX;
38402875878SEric Dumazet 	netif_keep_dst(dev);
385c3b89fbbSEric Dumazet 
386c3b89fbbSEric Dumazet 	dev->features		|= IPIP_FEATURES;
387c3b89fbbSEric Dumazet 	dev->hw_features	|= IPIP_FEATURES;
388fd58156eSPravin B Shelar 	ip_tunnel_setup(dev, ipip_net_id);
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds 
3913c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev)
3921da177e4SLinus Torvalds {
39323a12b14SStephen Hemminger 	struct ip_tunnel *tunnel = netdev_priv(dev);
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
3961da177e4SLinus Torvalds 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
3971da177e4SLinus Torvalds 
398473ab820STom Herbert 	tunnel->tun_hlen = 0;
399473ab820STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
400fd58156eSPravin B Shelar 	return ip_tunnel_init(dev);
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
403a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
404a8b8a889SMatthias Schiffer 				struct netlink_ext_ack *extack)
4051b69e7e6SSimon Horman {
4061b69e7e6SSimon Horman 	u8 proto;
4071b69e7e6SSimon Horman 
4081b69e7e6SSimon Horman 	if (!data || !data[IFLA_IPTUN_PROTO])
4091b69e7e6SSimon Horman 		return 0;
4101b69e7e6SSimon Horman 
4111b69e7e6SSimon Horman 	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
4121b69e7e6SSimon Horman 	if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
4131b69e7e6SSimon Horman 		return -EINVAL;
4141b69e7e6SSimon Horman 
4151b69e7e6SSimon Horman 	return 0;
4161b69e7e6SSimon Horman }
4171b69e7e6SSimon Horman 
418be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[],
4199830ad4cSCraig Gallek 			       struct ip_tunnel_parm *parms, bool *collect_md,
4209830ad4cSCraig Gallek 			       __u32 *fwmark)
421be42da0eSNicolas Dichtel {
422be42da0eSNicolas Dichtel 	memset(parms, 0, sizeof(*parms));
423be42da0eSNicolas Dichtel 
424be42da0eSNicolas Dichtel 	parms->iph.version = 4;
425be42da0eSNicolas Dichtel 	parms->iph.protocol = IPPROTO_IPIP;
426be42da0eSNicolas Dichtel 	parms->iph.ihl = 5;
427cfc7381bSAlexei Starovoitov 	*collect_md = false;
428be42da0eSNicolas Dichtel 
429be42da0eSNicolas Dichtel 	if (!data)
430be42da0eSNicolas Dichtel 		return;
431be42da0eSNicolas Dichtel 
432be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_LINK])
433be42da0eSNicolas Dichtel 		parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
434be42da0eSNicolas Dichtel 
435be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_LOCAL])
43667b61f6cSJiri Benc 		parms->iph.saddr = nla_get_in_addr(data[IFLA_IPTUN_LOCAL]);
437be42da0eSNicolas Dichtel 
438be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_REMOTE])
43967b61f6cSJiri Benc 		parms->iph.daddr = nla_get_in_addr(data[IFLA_IPTUN_REMOTE]);
440be42da0eSNicolas Dichtel 
441be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_TTL]) {
442be42da0eSNicolas Dichtel 		parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
443be42da0eSNicolas Dichtel 		if (parms->iph.ttl)
444be42da0eSNicolas Dichtel 			parms->iph.frag_off = htons(IP_DF);
445be42da0eSNicolas Dichtel 	}
446be42da0eSNicolas Dichtel 
447be42da0eSNicolas Dichtel 	if (data[IFLA_IPTUN_TOS])
448be42da0eSNicolas Dichtel 		parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
449be42da0eSNicolas Dichtel 
4501b69e7e6SSimon Horman 	if (data[IFLA_IPTUN_PROTO])
4511b69e7e6SSimon Horman 		parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
4521b69e7e6SSimon Horman 
453be42da0eSNicolas Dichtel 	if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
454be42da0eSNicolas Dichtel 		parms->iph.frag_off = htons(IP_DF);
455cfc7381bSAlexei Starovoitov 
456cfc7381bSAlexei Starovoitov 	if (data[IFLA_IPTUN_COLLECT_METADATA])
457cfc7381bSAlexei Starovoitov 		*collect_md = true;
4589830ad4cSCraig Gallek 
4599830ad4cSCraig Gallek 	if (data[IFLA_IPTUN_FWMARK])
4609830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
461be42da0eSNicolas Dichtel }
462be42da0eSNicolas Dichtel 
463473ab820STom Herbert /* This function returns true when ENCAP attributes are present in the nl msg */
464473ab820STom Herbert static bool ipip_netlink_encap_parms(struct nlattr *data[],
465473ab820STom Herbert 				     struct ip_tunnel_encap *ipencap)
466473ab820STom Herbert {
467473ab820STom Herbert 	bool ret = false;
468473ab820STom Herbert 
469473ab820STom Herbert 	memset(ipencap, 0, sizeof(*ipencap));
470473ab820STom Herbert 
471473ab820STom Herbert 	if (!data)
472473ab820STom Herbert 		return ret;
473473ab820STom Herbert 
474473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_TYPE]) {
475473ab820STom Herbert 		ret = true;
476473ab820STom Herbert 		ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]);
477473ab820STom Herbert 	}
478473ab820STom Herbert 
479473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_FLAGS]) {
480473ab820STom Herbert 		ret = true;
481473ab820STom Herbert 		ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]);
482473ab820STom Herbert 	}
483473ab820STom Herbert 
484473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_SPORT]) {
485473ab820STom Herbert 		ret = true;
4863e97fa70SSabrina Dubroca 		ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]);
487473ab820STom Herbert 	}
488473ab820STom Herbert 
489473ab820STom Herbert 	if (data[IFLA_IPTUN_ENCAP_DPORT]) {
490473ab820STom Herbert 		ret = true;
4913e97fa70SSabrina Dubroca 		ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]);
492473ab820STom Herbert 	}
493473ab820STom Herbert 
494473ab820STom Herbert 	return ret;
495473ab820STom Herbert }
496473ab820STom Herbert 
497be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev,
4987a3f4a18SMatthias Schiffer 			struct nlattr *tb[], struct nlattr *data[],
4997a3f4a18SMatthias Schiffer 			struct netlink_ext_ack *extack)
500be42da0eSNicolas Dichtel {
501cfc7381bSAlexei Starovoitov 	struct ip_tunnel *t = netdev_priv(dev);
502fd58156eSPravin B Shelar 	struct ip_tunnel_parm p;
503473ab820STom Herbert 	struct ip_tunnel_encap ipencap;
5049830ad4cSCraig Gallek 	__u32 fwmark = 0;
505473ab820STom Herbert 
506473ab820STom Herbert 	if (ipip_netlink_encap_parms(data, &ipencap)) {
507473ab820STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
508473ab820STom Herbert 
509473ab820STom Herbert 		if (err < 0)
510473ab820STom Herbert 			return err;
511473ab820STom Herbert 	}
512be42da0eSNicolas Dichtel 
5139830ad4cSCraig Gallek 	ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
5149830ad4cSCraig Gallek 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
515be42da0eSNicolas Dichtel }
516be42da0eSNicolas Dichtel 
517be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
518ad744b22SMatthias Schiffer 			   struct nlattr *data[],
519ad744b22SMatthias Schiffer 			   struct netlink_ext_ack *extack)
520be42da0eSNicolas Dichtel {
5219830ad4cSCraig Gallek 	struct ip_tunnel *t = netdev_priv(dev);
522be42da0eSNicolas Dichtel 	struct ip_tunnel_parm p;
523473ab820STom Herbert 	struct ip_tunnel_encap ipencap;
524cfc7381bSAlexei Starovoitov 	bool collect_md;
5259830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
526473ab820STom Herbert 
527473ab820STom Herbert 	if (ipip_netlink_encap_parms(data, &ipencap)) {
528473ab820STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
529473ab820STom Herbert 
530473ab820STom Herbert 		if (err < 0)
531473ab820STom Herbert 			return err;
532473ab820STom Herbert 	}
533be42da0eSNicolas Dichtel 
5349830ad4cSCraig Gallek 	ipip_netlink_parms(data, &p, &collect_md, &fwmark);
535cfc7381bSAlexei Starovoitov 	if (collect_md)
536cfc7381bSAlexei Starovoitov 		return -EINVAL;
537be42da0eSNicolas Dichtel 
538be42da0eSNicolas Dichtel 	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
539be42da0eSNicolas Dichtel 	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
540be42da0eSNicolas Dichtel 		return -EINVAL;
541be42da0eSNicolas Dichtel 
5429830ad4cSCraig Gallek 	return ip_tunnel_changelink(dev, tb, &p, fwmark);
543be42da0eSNicolas Dichtel }
544be42da0eSNicolas Dichtel 
5450974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev)
5460974658dSNicolas Dichtel {
5470974658dSNicolas Dichtel 	return
5480974658dSNicolas Dichtel 		/* IFLA_IPTUN_LINK */
5490974658dSNicolas Dichtel 		nla_total_size(4) +
5500974658dSNicolas Dichtel 		/* IFLA_IPTUN_LOCAL */
5510974658dSNicolas Dichtel 		nla_total_size(4) +
5520974658dSNicolas Dichtel 		/* IFLA_IPTUN_REMOTE */
5530974658dSNicolas Dichtel 		nla_total_size(4) +
5540974658dSNicolas Dichtel 		/* IFLA_IPTUN_TTL */
5550974658dSNicolas Dichtel 		nla_total_size(1) +
5560974658dSNicolas Dichtel 		/* IFLA_IPTUN_TOS */
5570974658dSNicolas Dichtel 		nla_total_size(1) +
5581b69e7e6SSimon Horman 		/* IFLA_IPTUN_PROTO */
5591b69e7e6SSimon Horman 		nla_total_size(1) +
560befe2aa1SNicolas Dichtel 		/* IFLA_IPTUN_PMTUDISC */
561befe2aa1SNicolas Dichtel 		nla_total_size(1) +
562473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_TYPE */
563473ab820STom Herbert 		nla_total_size(2) +
564473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_FLAGS */
565473ab820STom Herbert 		nla_total_size(2) +
566473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_SPORT */
567473ab820STom Herbert 		nla_total_size(2) +
568473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_DPORT */
569473ab820STom Herbert 		nla_total_size(2) +
570cfc7381bSAlexei Starovoitov 		/* IFLA_IPTUN_COLLECT_METADATA */
571cfc7381bSAlexei Starovoitov 		nla_total_size(0) +
5729830ad4cSCraig Gallek 		/* IFLA_IPTUN_FWMARK */
5739830ad4cSCraig Gallek 		nla_total_size(4) +
5740974658dSNicolas Dichtel 		0;
5750974658dSNicolas Dichtel }
5760974658dSNicolas Dichtel 
5770974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
5780974658dSNicolas Dichtel {
5790974658dSNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
5800974658dSNicolas Dichtel 	struct ip_tunnel_parm *parm = &tunnel->parms;
5810974658dSNicolas Dichtel 
5820974658dSNicolas Dichtel 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
583930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
584930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
5850974658dSNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
586befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
5871b69e7e6SSimon Horman 	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
588befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
5899830ad4cSCraig Gallek 		       !!(parm->iph.frag_off & htons(IP_DF))) ||
5909830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
5910974658dSNicolas Dichtel 		goto nla_put_failure;
592473ab820STom Herbert 
593473ab820STom Herbert 	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
594473ab820STom Herbert 			tunnel->encap.type) ||
5953e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
596473ab820STom Herbert 			 tunnel->encap.sport) ||
5973e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
598473ab820STom Herbert 			 tunnel->encap.dport) ||
599473ab820STom Herbert 	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
600e1b2cb65STom Herbert 			tunnel->encap.flags))
601473ab820STom Herbert 		goto nla_put_failure;
602473ab820STom Herbert 
603cfc7381bSAlexei Starovoitov 	if (tunnel->collect_md)
604cfc7381bSAlexei Starovoitov 		if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
605cfc7381bSAlexei Starovoitov 			goto nla_put_failure;
6060974658dSNicolas Dichtel 	return 0;
6070974658dSNicolas Dichtel 
6080974658dSNicolas Dichtel nla_put_failure:
6090974658dSNicolas Dichtel 	return -EMSGSIZE;
6100974658dSNicolas Dichtel }
6110974658dSNicolas Dichtel 
612be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
613be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
614be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
615be42da0eSNicolas Dichtel 	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
616be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
617be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
6181b69e7e6SSimon Horman 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
619be42da0eSNicolas Dichtel 	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
620473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
621473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
622473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
623473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
624cfc7381bSAlexei Starovoitov 	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
6259830ad4cSCraig Gallek 	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
626be42da0eSNicolas Dichtel };
627be42da0eSNicolas Dichtel 
6280974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = {
6290974658dSNicolas Dichtel 	.kind		= "ipip",
6300974658dSNicolas Dichtel 	.maxtype	= IFLA_IPTUN_MAX,
631be42da0eSNicolas Dichtel 	.policy		= ipip_policy,
6320974658dSNicolas Dichtel 	.priv_size	= sizeof(struct ip_tunnel),
633be42da0eSNicolas Dichtel 	.setup		= ipip_tunnel_setup,
6341b69e7e6SSimon Horman 	.validate	= ipip_tunnel_validate,
635be42da0eSNicolas Dichtel 	.newlink	= ipip_newlink,
636be42da0eSNicolas Dichtel 	.changelink	= ipip_changelink,
637fd58156eSPravin B Shelar 	.dellink	= ip_tunnel_dellink,
6380974658dSNicolas Dichtel 	.get_size	= ipip_get_size,
6390974658dSNicolas Dichtel 	.fill_info	= ipip_fill_info,
6401728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
6410974658dSNicolas Dichtel };
6420974658dSNicolas Dichtel 
6436dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = {
6441da177e4SLinus Torvalds 	.handler	=	ipip_rcv,
6451da177e4SLinus Torvalds 	.err_handler	=	ipip_err,
646d2acc347SHerbert Xu 	.priority	=	1,
6471da177e4SLinus Torvalds };
6481da177e4SLinus Torvalds 
6491b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6501b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = {
6511b69e7e6SSimon Horman 	.handler	=	mplsip_rcv,
6521b69e7e6SSimon Horman 	.err_handler	=	ipip_err,
6531b69e7e6SSimon Horman 	.priority	=	1,
6541b69e7e6SSimon Horman };
6551b69e7e6SSimon Horman #endif
6561b69e7e6SSimon Horman 
6572c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net)
65810dc4c7bSPavel Emelyanov {
659fd58156eSPravin B Shelar 	return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
66010dc4c7bSPavel Emelyanov }
66110dc4c7bSPavel Emelyanov 
6622c8c1e72SAlexey Dobriyan static void __net_exit ipip_exit_net(struct net *net)
66310dc4c7bSPavel Emelyanov {
664fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
6656c742e71SNicolas Dichtel 	ip_tunnel_delete_net(itn, &ipip_link_ops);
66610dc4c7bSPavel Emelyanov }
66710dc4c7bSPavel Emelyanov 
66810dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = {
66910dc4c7bSPavel Emelyanov 	.init = ipip_init_net,
67010dc4c7bSPavel Emelyanov 	.exit = ipip_exit_net,
67186de8a63SEric W. Biederman 	.id   = &ipip_net_id,
672fd58156eSPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
67310dc4c7bSPavel Emelyanov };
67410dc4c7bSPavel Emelyanov 
6751da177e4SLinus Torvalds static int __init ipip_init(void)
6761da177e4SLinus Torvalds {
6771da177e4SLinus Torvalds 	int err;
6781da177e4SLinus Torvalds 
6791b69e7e6SSimon Horman 	pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
6801da177e4SLinus Torvalds 
68186de8a63SEric W. Biederman 	err = register_pernet_device(&ipip_net_ops);
682d5aa407fSAlexey Dobriyan 	if (err < 0)
683d5aa407fSAlexey Dobriyan 		return err;
684d5aa407fSAlexey Dobriyan 	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
685d5aa407fSAlexey Dobriyan 	if (err < 0) {
686058bd4d2SJoe Perches 		pr_info("%s: can't register tunnel\n", __func__);
6871b69e7e6SSimon Horman 		goto xfrm_tunnel_ipip_failed;
688d5aa407fSAlexey Dobriyan 	}
6891b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6901b69e7e6SSimon Horman 	err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
6911b69e7e6SSimon Horman 	if (err < 0) {
6921b69e7e6SSimon Horman 		pr_info("%s: can't register tunnel\n", __func__);
6931b69e7e6SSimon Horman 		goto xfrm_tunnel_mplsip_failed;
6941b69e7e6SSimon Horman 	}
6951b69e7e6SSimon Horman #endif
6960974658dSNicolas Dichtel 	err = rtnl_link_register(&ipip_link_ops);
6970974658dSNicolas Dichtel 	if (err < 0)
6980974658dSNicolas Dichtel 		goto rtnl_link_failed;
6990974658dSNicolas Dichtel 
7000974658dSNicolas Dichtel out:
701b9855c54SPavel Emelyanov 	return err;
7020974658dSNicolas Dichtel 
7030974658dSNicolas Dichtel rtnl_link_failed:
7041b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
7051b69e7e6SSimon Horman 	xfrm4_tunnel_deregister(&mplsip_handler, AF_INET);
7061b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed:
7071b69e7e6SSimon Horman 
7081b69e7e6SSimon Horman #endif
7090974658dSNicolas Dichtel 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
7101b69e7e6SSimon Horman xfrm_tunnel_ipip_failed:
7110974658dSNicolas Dichtel 	unregister_pernet_device(&ipip_net_ops);
7120974658dSNicolas Dichtel 	goto out;
7131da177e4SLinus Torvalds }
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds static void __exit ipip_fini(void)
7161da177e4SLinus Torvalds {
7170974658dSNicolas Dichtel 	rtnl_link_unregister(&ipip_link_ops);
718c0d56408SKazunori MIYAZAWA 	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
719058bd4d2SJoe Perches 		pr_info("%s: can't deregister tunnel\n", __func__);
7201b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
7211b69e7e6SSimon Horman 	if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
7221b69e7e6SSimon Horman 		pr_info("%s: can't deregister tunnel\n", __func__);
7231b69e7e6SSimon Horman #endif
72486de8a63SEric W. Biederman 	unregister_pernet_device(&ipip_net_ops);
7251da177e4SLinus Torvalds }
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds module_init(ipip_init);
7281da177e4SLinus Torvalds module_exit(ipip_fini);
7291da177e4SLinus Torvalds MODULE_LICENSE("GPL");
730f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip");
7318909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0");
732