xref: /linux/net/ipv4/ipip.c (revision ac931d4cdec3df8b6eac3bc40a6871123021f078)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	Linux NET3:	IP/IP protocol decoder.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *	Authors:
61da177e4SLinus Torvalds  *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *	Fixes:
91da177e4SLinus Torvalds  *		Alan Cox	:	Merged and made usable non modular (its so tiny its silly as
101da177e4SLinus Torvalds  *					a module taking up 2 pages).
111da177e4SLinus Torvalds  *		Alan Cox	: 	Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
121da177e4SLinus Torvalds  *					to keep ip_forward happy.
131da177e4SLinus Torvalds  *		Alan Cox	:	More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
141da177e4SLinus Torvalds  *		Kai Schulte	:	Fixed #defines for IP_FIREWALL->FIREWALL
151da177e4SLinus Torvalds  *              David Woodhouse :       Perform some basic ICMP handling.
161da177e4SLinus Torvalds  *                                      IPIP Routing without decapsulation.
171da177e4SLinus Torvalds  *              Carlos Picoto   :       GRE over IP support
181da177e4SLinus Torvalds  *		Alexey Kuznetsov:	Reworked. Really, now it is truncated version of ipv4/ip_gre.c.
191da177e4SLinus Torvalds  *					I do not want to merge them together.
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds /* tunnel.c: an IP tunnel driver
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds 	The purpose of this driver is to provide an IP tunnel through
251da177e4SLinus Torvalds 	which you can tunnel network traffic transparently across subnets.
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 	This was written by looking at Nick Holloway's dummy driver
281da177e4SLinus Torvalds 	Thanks for the great code!
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds 		-Sam Lantinga	(slouken@cs.ucdavis.edu)  02/01/95
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 	Minor tweaks:
331da177e4SLinus Torvalds 		Cleaned up the code a little and added some pre-1.3.0 tweaks.
341da177e4SLinus Torvalds 		dev->hard_header/hard_header_len changed to use no headers.
351da177e4SLinus Torvalds 		Comments/bracketing tweaked.
361da177e4SLinus Torvalds 		Made the tunnels use dev->name not tunnel: when error reporting.
371da177e4SLinus Torvalds 		Added tx_dropped stat
381da177e4SLinus Torvalds 
39113aa838SAlan Cox 		-Alan Cox	(alan@lxorguk.ukuu.org.uk) 21 March 95
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 	Reworked:
421da177e4SLinus Torvalds 		Changed to tunnel to destination gateway in addition to the
431da177e4SLinus Torvalds 			tunnel's pointopoint address
441da177e4SLinus Torvalds 		Almost completely rewritten
451da177e4SLinus Torvalds 		Note:  There is currently no firewall or ICMP handling done.
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 		-Sam Lantinga	(slouken@cs.ucdavis.edu) 02/13/96
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds */
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /* Things I wish I had known when writing the tunnel driver:
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	When the tunnel_xmit() function is called, the skb contains the
541da177e4SLinus Torvalds 	packet to be sent (plus a great deal of extra info), and dev
551da177e4SLinus Torvalds 	contains the tunnel device that _we_ are.
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	When we are passed a packet, we are expected to fill in the
581da177e4SLinus Torvalds 	source address with our source IP address.
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	What is the proper way to allocate, copy and free a buffer?
611da177e4SLinus Torvalds 	After you allocate it, it is a "0 length" chunk of memory
621da177e4SLinus Torvalds 	starting at zero.  If you want to add headers to the buffer
631da177e4SLinus Torvalds 	later, you'll have to call "skb_reserve(skb, amount)" with
641da177e4SLinus Torvalds 	the amount of memory you want reserved.  Then, you call
651da177e4SLinus Torvalds 	"skb_put(skb, amount)" with the amount of space you want in
661da177e4SLinus Torvalds 	the buffer.  skb_put() returns a pointer to the top (#0) of
671da177e4SLinus Torvalds 	that buffer.  skb->len is set to the amount of space you have
681da177e4SLinus Torvalds 	"allocated" with skb_put().  You can then write up to skb->len
691da177e4SLinus Torvalds 	bytes to that buffer.  If you need more, you can call skb_put()
701da177e4SLinus Torvalds 	again with the additional amount of space you need.  You can
711da177e4SLinus Torvalds 	find out how much more space you can allocate by calling
721da177e4SLinus Torvalds 	"skb_tailroom(skb)".
731da177e4SLinus Torvalds 	Now, to add header space, call "skb_push(skb, header_len)".
741da177e4SLinus Torvalds 	This creates space at the beginning of the buffer and returns
751da177e4SLinus Torvalds 	a pointer to this new space.  If later you need to strip a
761da177e4SLinus Torvalds 	header from a buffer, call "skb_pull(skb, header_len)".
771da177e4SLinus Torvalds 	skb_headroom() will return how much space is left at the top
781da177e4SLinus Torvalds 	of the buffer (before the main data).  Remember, this headroom
791da177e4SLinus Torvalds 	space must be reserved before the skb_put() function is called.
801da177e4SLinus Torvalds 	*/
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds /*
831da177e4SLinus Torvalds    This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds    For comments look at net/ipv4/ip_gre.c --ANK
861da177e4SLinus Torvalds  */
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds 
894fc268d2SRandy Dunlap #include <linux/capability.h>
901da177e4SLinus Torvalds #include <linux/module.h>
911da177e4SLinus Torvalds #include <linux/types.h>
921da177e4SLinus Torvalds #include <linux/kernel.h>
935a0e3ad6STejun Heo #include <linux/slab.h>
947c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
951da177e4SLinus Torvalds #include <linux/skbuff.h>
961da177e4SLinus Torvalds #include <linux/netdevice.h>
971da177e4SLinus Torvalds #include <linux/in.h>
981da177e4SLinus Torvalds #include <linux/tcp.h>
991da177e4SLinus Torvalds #include <linux/udp.h>
1001da177e4SLinus Torvalds #include <linux/if_arp.h>
1011da177e4SLinus Torvalds #include <linux/init.h>
1021da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
10346f25dffSKris Katterjohn #include <linux/if_ether.h>
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds #include <net/sock.h>
1061da177e4SLinus Torvalds #include <net/ip.h>
1071da177e4SLinus Torvalds #include <net/icmp.h>
108c5441932SPravin B Shelar #include <net/ip_tunnels.h>
1091da177e4SLinus Torvalds #include <net/inet_ecn.h>
1101da177e4SLinus Torvalds #include <net/xfrm.h>
11110dc4c7bSPavel Emelyanov #include <net/net_namespace.h>
11210dc4c7bSPavel Emelyanov #include <net/netns/generic.h>
113cfc7381bSAlexei Starovoitov #include <net/dst_metadata.h>
1141da177e4SLinus Torvalds 
115eccc1bb8Sstephen hemminger static bool log_ecn_error = true;
116eccc1bb8Sstephen hemminger module_param(log_ecn_error, bool, 0644);
117eccc1bb8Sstephen hemminger MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
118eccc1bb8Sstephen hemminger 
119c7d03a00SAlexey Dobriyan static unsigned int ipip_net_id __read_mostly;
12010dc4c7bSPavel Emelyanov 
1213c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev);
1220974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly;
1231da177e4SLinus Torvalds 
124d2acc347SHerbert Xu static int ipip_err(struct sk_buff *skb, u32 info)
1251da177e4SLinus Torvalds {
126071f92d0SRami Rosen 	/* All the routers (except for Linux) return only
127f3594f0aSXin Long 	 * 8 bytes of packet payload. It means, that precise relaying of
128f3594f0aSXin Long 	 * ICMP in the real Internet is absolutely infeasible.
1291da177e4SLinus Torvalds 	 */
130fd58156eSPravin B Shelar 	struct net *net = dev_net(skb->dev);
131fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
132b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
133fd58156eSPravin B Shelar 	const int type = icmp_hdr(skb)->type;
134fd58156eSPravin B Shelar 	const int code = icmp_hdr(skb)->code;
135f3594f0aSXin Long 	struct ip_tunnel *t;
136f3594f0aSXin Long 	int err = 0;
1371da177e4SLinus Torvalds 
13832bbd879SStefano Brivio 	t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
13932bbd879SStefano Brivio 			     iph->daddr, iph->saddr, 0);
14032bbd879SStefano Brivio 	if (!t) {
14132bbd879SStefano Brivio 		err = -ENOENT;
14232bbd879SStefano Brivio 		goto out;
14332bbd879SStefano Brivio 	}
14432bbd879SStefano Brivio 
145f3594f0aSXin Long 	switch (type) {
146f3594f0aSXin Long 	case ICMP_DEST_UNREACH:
147f3594f0aSXin Long 		switch (code) {
148f3594f0aSXin Long 		case ICMP_SR_FAILED:
149f3594f0aSXin Long 			/* Impossible event. */
150f3594f0aSXin Long 			goto out;
151f3594f0aSXin Long 		default:
152f3594f0aSXin Long 			/* All others are translated to HOST_UNREACH.
153f3594f0aSXin Long 			 * rfc2003 contains "deep thoughts" about NET_UNREACH,
154f3594f0aSXin Long 			 * I believe they are just ether pollution. --ANK
155f3594f0aSXin Long 			 */
156f3594f0aSXin Long 			break;
157f3594f0aSXin Long 		}
158f3594f0aSXin Long 		break;
159f3594f0aSXin Long 
160f3594f0aSXin Long 	case ICMP_TIME_EXCEEDED:
161f3594f0aSXin Long 		if (code != ICMP_EXC_TTL)
162f3594f0aSXin Long 			goto out;
163f3594f0aSXin Long 		break;
164f3594f0aSXin Long 
165f3594f0aSXin Long 	case ICMP_REDIRECT:
166f3594f0aSXin Long 		break;
167f3594f0aSXin Long 
168f3594f0aSXin Long 	default:
169f3594f0aSXin Long 		goto out;
170f3594f0aSXin Long 	}
171f3594f0aSXin Long 
17236393395SDavid S. Miller 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
173d888f396SMaciej Żenczykowski 		ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol);
17436393395SDavid S. Miller 		goto out;
17536393395SDavid S. Miller 	}
17636393395SDavid S. Miller 
17755be7a9cSDavid S. Miller 	if (type == ICMP_REDIRECT) {
1781042caa7SMaciej Żenczykowski 		ipv4_redirect(skb, net, t->parms.link, iph->protocol);
17955be7a9cSDavid S. Miller 		goto out;
18055be7a9cSDavid S. Miller 	}
18155be7a9cSDavid S. Miller 
182f3594f0aSXin Long 	if (t->parms.iph.daddr == 0) {
183f3594f0aSXin Long 		err = -ENOENT;
1841da177e4SLinus Torvalds 		goto out;
185f3594f0aSXin Long 	}
186d2acc347SHerbert Xu 
1871da177e4SLinus Torvalds 	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
1881da177e4SLinus Torvalds 		goto out;
1891da177e4SLinus Torvalds 
19026d94b46SWei Yongjun 	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
1911da177e4SLinus Torvalds 		t->err_count++;
1921da177e4SLinus Torvalds 	else
1931da177e4SLinus Torvalds 		t->err_count = 1;
1941da177e4SLinus Torvalds 	t->err_time = jiffies;
195b0558ef2Sstephen hemminger 
196fd58156eSPravin B Shelar out:
197d2acc347SHerbert Xu 	return err;
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds 
2001b69e7e6SSimon Horman static const struct tnl_ptk_info ipip_tpi = {
201fd58156eSPravin B Shelar 	/* no tunnel info required for ipip. */
202fd58156eSPravin B Shelar 	.proto = htons(ETH_P_IP),
203fd58156eSPravin B Shelar };
204fd58156eSPravin B Shelar 
2051b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2061b69e7e6SSimon Horman static const struct tnl_ptk_info mplsip_tpi = {
2071b69e7e6SSimon Horman 	/* no tunnel info required for mplsip. */
2081b69e7e6SSimon Horman 	.proto = htons(ETH_P_MPLS_UC),
2091b69e7e6SSimon Horman };
2101b69e7e6SSimon Horman #endif
2111b69e7e6SSimon Horman 
2121b69e7e6SSimon Horman static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
2131da177e4SLinus Torvalds {
214fd58156eSPravin B Shelar 	struct net *net = dev_net(skb->dev);
215fd58156eSPravin B Shelar 	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
216cfc7381bSAlexei Starovoitov 	struct metadata_dst *tun_dst = NULL;
2171da177e4SLinus Torvalds 	struct ip_tunnel *tunnel;
2183d7b46cdSPravin B Shelar 	const struct iphdr *iph;
2191da177e4SLinus Torvalds 
2203d7b46cdSPravin B Shelar 	iph = ip_hdr(skb);
221fd58156eSPravin B Shelar 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
222fd58156eSPravin B Shelar 			iph->saddr, iph->daddr, 0);
223fd58156eSPravin B Shelar 	if (tunnel) {
2241b69e7e6SSimon Horman 		const struct tnl_ptk_info *tpi;
2251b69e7e6SSimon Horman 
2261b69e7e6SSimon Horman 		if (tunnel->parms.iph.protocol != ipproto &&
2271b69e7e6SSimon Horman 		    tunnel->parms.iph.protocol != 0)
2281b69e7e6SSimon Horman 			goto drop;
2291b69e7e6SSimon Horman 
230eccc1bb8Sstephen hemminger 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
231eccc1bb8Sstephen hemminger 			goto drop;
2321b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2331b69e7e6SSimon Horman 		if (ipproto == IPPROTO_MPLS)
2341b69e7e6SSimon Horman 			tpi = &mplsip_tpi;
2351b69e7e6SSimon Horman 		else
2361b69e7e6SSimon Horman #endif
2371b69e7e6SSimon Horman 			tpi = &ipip_tpi;
2381b69e7e6SSimon Horman 		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
239737e828bSLi Hongjun 			goto drop;
240cfc7381bSAlexei Starovoitov 		if (tunnel->collect_md) {
241cfc7381bSAlexei Starovoitov 			tun_dst = ip_tun_rx_dst(skb, 0, 0, 0);
242cfc7381bSAlexei Starovoitov 			if (!tun_dst)
243cfc7381bSAlexei Starovoitov 				return 0;
244*ac931d4cSChristian Ehrig 			ip_tunnel_md_udp_encap(skb, &tun_dst->u.tun_info);
245cfc7381bSAlexei Starovoitov 		}
2467ad136fdSGuillaume Nault 		skb_reset_mac_header(skb);
2477ad136fdSGuillaume Nault 
248cfc7381bSAlexei Starovoitov 		return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
2491da177e4SLinus Torvalds 	}
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	return -1;
252eccc1bb8Sstephen hemminger 
253eccc1bb8Sstephen hemminger drop:
254eccc1bb8Sstephen hemminger 	kfree_skb(skb);
255eccc1bb8Sstephen hemminger 	return 0;
2561da177e4SLinus Torvalds }
2571da177e4SLinus Torvalds 
2581b69e7e6SSimon Horman static int ipip_rcv(struct sk_buff *skb)
2591b69e7e6SSimon Horman {
2601b69e7e6SSimon Horman 	return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
2611b69e7e6SSimon Horman }
2621b69e7e6SSimon Horman 
2631b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
2641b69e7e6SSimon Horman static int mplsip_rcv(struct sk_buff *skb)
2651b69e7e6SSimon Horman {
2661b69e7e6SSimon Horman 	return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
2671b69e7e6SSimon Horman }
2681b69e7e6SSimon Horman #endif
2691b69e7e6SSimon Horman 
2701da177e4SLinus Torvalds /*
2711da177e4SLinus Torvalds  *	This function assumes it is being called from dev_queue_xmit()
2721da177e4SLinus Torvalds  *	and that skb is filled properly by that function.
2731da177e4SLinus Torvalds  */
2741b69e7e6SSimon Horman static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
2751b69e7e6SSimon Horman 				    struct net_device *dev)
2761da177e4SLinus Torvalds {
2772941a486SPatrick McHardy 	struct ip_tunnel *tunnel = netdev_priv(dev);
278b71d1d42SEric Dumazet 	const struct iphdr  *tiph = &tunnel->parms.iph;
2791b69e7e6SSimon Horman 	u8 ipproto;
2801da177e4SLinus Torvalds 
28147d858d0SHaishuang Yan 	if (!pskb_inet_may_pull(skb))
28247d858d0SHaishuang Yan 		goto tx_error;
28347d858d0SHaishuang Yan 
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)
306c8b34e68Swenxu 		ip_md_tunnel_xmit(skb, dev, ipproto, 0);
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 
314c4794d22SEric Dumazet 	DEV_STATS_INC(dev, 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
333607259a6SChristoph Hellwig ipip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
3341da177e4SLinus Torvalds {
3353b7b514fSCong Wang 	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
336607259a6SChristoph Hellwig 		if (p->iph.version != 4 ||
337607259a6SChristoph Hellwig 		    !ipip_tunnel_ioctl_verify_protocol(p->iph.protocol) ||
338607259a6SChristoph Hellwig 		    p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)))
339fd58156eSPravin B Shelar 			return -EINVAL;
3403b7b514fSCong Wang 	}
3413b7b514fSCong Wang 
342607259a6SChristoph Hellwig 	p->i_key = p->o_key = 0;
343607259a6SChristoph Hellwig 	p->i_flags = p->o_flags = 0;
344607259a6SChristoph Hellwig 	return ip_tunnel_ctl(dev, p, cmd);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
34723a12b14SStephen Hemminger static const struct net_device_ops ipip_netdev_ops = {
348fd58156eSPravin B Shelar 	.ndo_init       = ipip_tunnel_init,
349fd58156eSPravin B Shelar 	.ndo_uninit     = ip_tunnel_uninit,
35023a12b14SStephen Hemminger 	.ndo_start_xmit	= ipip_tunnel_xmit,
3513e7a1c7cSArnd Bergmann 	.ndo_siocdevprivate = ip_tunnel_siocdevprivate,
352fd58156eSPravin B Shelar 	.ndo_change_mtu = ip_tunnel_change_mtu,
35398d7fc46SHeiner Kallweit 	.ndo_get_stats64 = dev_get_tstats64,
3541e99584bSNicolas Dichtel 	.ndo_get_iflink = ip_tunnel_get_iflink,
355607259a6SChristoph Hellwig 	.ndo_tunnel_ctl	= ipip_tunnel_ctl,
35623a12b14SStephen Hemminger };
35723a12b14SStephen Hemminger 
358c3b89fbbSEric Dumazet #define IPIP_FEATURES (NETIF_F_SG |		\
359c3b89fbbSEric Dumazet 		       NETIF_F_FRAGLIST |	\
360c3b89fbbSEric Dumazet 		       NETIF_F_HIGHDMA |	\
361cb32f511SEric Dumazet 		       NETIF_F_GSO_SOFTWARE |	\
362c3b89fbbSEric Dumazet 		       NETIF_F_HW_CSUM)
363c3b89fbbSEric Dumazet 
3641da177e4SLinus Torvalds static void ipip_tunnel_setup(struct net_device *dev)
3651da177e4SLinus Torvalds {
36623a12b14SStephen Hemminger 	dev->netdev_ops		= &ipip_netdev_ops;
367e53ac932SJason A. Donenfeld 	dev->header_ops		= &ip_tunnel_header_ops;
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 	dev->type		= ARPHRD_TUNNEL;
3701da177e4SLinus Torvalds 	dev->flags		= IFF_NOARP;
3711da177e4SLinus Torvalds 	dev->addr_len		= 4;
372153f0943SEric Dumazet 	dev->features		|= NETIF_F_LLTX;
37302875878SEric Dumazet 	netif_keep_dst(dev);
374c3b89fbbSEric Dumazet 
375c3b89fbbSEric Dumazet 	dev->features		|= IPIP_FEATURES;
376c3b89fbbSEric Dumazet 	dev->hw_features	|= IPIP_FEATURES;
377fd58156eSPravin B Shelar 	ip_tunnel_setup(dev, ipip_net_id);
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds 
3803c97af99SEric Dumazet static int ipip_tunnel_init(struct net_device *dev)
3811da177e4SLinus Torvalds {
38223a12b14SStephen Hemminger 	struct ip_tunnel *tunnel = netdev_priv(dev);
3831da177e4SLinus Torvalds 
3845a1b7e1aSJakub Kicinski 	__dev_addr_set(dev, &tunnel->parms.iph.saddr, 4);
3851da177e4SLinus Torvalds 	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
3861da177e4SLinus Torvalds 
387473ab820STom Herbert 	tunnel->tun_hlen = 0;
388473ab820STom Herbert 	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
389fd58156eSPravin B Shelar 	return ip_tunnel_init(dev);
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds 
392a8b8a889SMatthias Schiffer static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
393a8b8a889SMatthias Schiffer 				struct netlink_ext_ack *extack)
3941b69e7e6SSimon Horman {
3951b69e7e6SSimon Horman 	u8 proto;
3961b69e7e6SSimon Horman 
3971b69e7e6SSimon Horman 	if (!data || !data[IFLA_IPTUN_PROTO])
3981b69e7e6SSimon Horman 		return 0;
3991b69e7e6SSimon Horman 
4001b69e7e6SSimon Horman 	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
4011b69e7e6SSimon Horman 	if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
4021b69e7e6SSimon Horman 		return -EINVAL;
4031b69e7e6SSimon Horman 
4041b69e7e6SSimon Horman 	return 0;
4051b69e7e6SSimon Horman }
4061b69e7e6SSimon Horman 
407be42da0eSNicolas Dichtel static void ipip_netlink_parms(struct nlattr *data[],
4089830ad4cSCraig Gallek 			       struct ip_tunnel_parm *parms, bool *collect_md,
4099830ad4cSCraig Gallek 			       __u32 *fwmark)
410be42da0eSNicolas Dichtel {
411be42da0eSNicolas Dichtel 	memset(parms, 0, sizeof(*parms));
412be42da0eSNicolas Dichtel 
413be42da0eSNicolas Dichtel 	parms->iph.version = 4;
414be42da0eSNicolas Dichtel 	parms->iph.protocol = IPPROTO_IPIP;
415be42da0eSNicolas Dichtel 	parms->iph.ihl = 5;
416cfc7381bSAlexei Starovoitov 	*collect_md = false;
417be42da0eSNicolas Dichtel 
418be42da0eSNicolas Dichtel 	if (!data)
419be42da0eSNicolas Dichtel 		return;
420be42da0eSNicolas Dichtel 
421b86fca80SLiu Jian 	ip_tunnel_netlink_parms(data, parms);
422cfc7381bSAlexei Starovoitov 
423cfc7381bSAlexei Starovoitov 	if (data[IFLA_IPTUN_COLLECT_METADATA])
424cfc7381bSAlexei Starovoitov 		*collect_md = true;
4259830ad4cSCraig Gallek 
4269830ad4cSCraig Gallek 	if (data[IFLA_IPTUN_FWMARK])
4279830ad4cSCraig Gallek 		*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
428be42da0eSNicolas Dichtel }
429be42da0eSNicolas Dichtel 
430be42da0eSNicolas Dichtel static int ipip_newlink(struct net *src_net, struct net_device *dev,
4317a3f4a18SMatthias Schiffer 			struct nlattr *tb[], struct nlattr *data[],
4327a3f4a18SMatthias Schiffer 			struct netlink_ext_ack *extack)
433be42da0eSNicolas Dichtel {
434cfc7381bSAlexei Starovoitov 	struct ip_tunnel *t = netdev_priv(dev);
435fd58156eSPravin B Shelar 	struct ip_tunnel_parm p;
436473ab820STom Herbert 	struct ip_tunnel_encap ipencap;
4379830ad4cSCraig Gallek 	__u32 fwmark = 0;
438473ab820STom Herbert 
439537dd2d9SLiu Jian 	if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
440473ab820STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
441473ab820STom Herbert 
442473ab820STom Herbert 		if (err < 0)
443473ab820STom Herbert 			return err;
444473ab820STom Herbert 	}
445be42da0eSNicolas Dichtel 
4469830ad4cSCraig Gallek 	ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
4479830ad4cSCraig Gallek 	return ip_tunnel_newlink(dev, tb, &p, fwmark);
448be42da0eSNicolas Dichtel }
449be42da0eSNicolas Dichtel 
450be42da0eSNicolas Dichtel static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
451ad744b22SMatthias Schiffer 			   struct nlattr *data[],
452ad744b22SMatthias Schiffer 			   struct netlink_ext_ack *extack)
453be42da0eSNicolas Dichtel {
4549830ad4cSCraig Gallek 	struct ip_tunnel *t = netdev_priv(dev);
455be42da0eSNicolas Dichtel 	struct ip_tunnel_parm p;
456473ab820STom Herbert 	struct ip_tunnel_encap ipencap;
457cfc7381bSAlexei Starovoitov 	bool collect_md;
4589830ad4cSCraig Gallek 	__u32 fwmark = t->fwmark;
459473ab820STom Herbert 
460537dd2d9SLiu Jian 	if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
461473ab820STom Herbert 		int err = ip_tunnel_encap_setup(t, &ipencap);
462473ab820STom Herbert 
463473ab820STom Herbert 		if (err < 0)
464473ab820STom Herbert 			return err;
465473ab820STom Herbert 	}
466be42da0eSNicolas Dichtel 
4679830ad4cSCraig Gallek 	ipip_netlink_parms(data, &p, &collect_md, &fwmark);
468cfc7381bSAlexei Starovoitov 	if (collect_md)
469cfc7381bSAlexei Starovoitov 		return -EINVAL;
470be42da0eSNicolas Dichtel 
471be42da0eSNicolas Dichtel 	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
472be42da0eSNicolas Dichtel 	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
473be42da0eSNicolas Dichtel 		return -EINVAL;
474be42da0eSNicolas Dichtel 
4759830ad4cSCraig Gallek 	return ip_tunnel_changelink(dev, tb, &p, fwmark);
476be42da0eSNicolas Dichtel }
477be42da0eSNicolas Dichtel 
4780974658dSNicolas Dichtel static size_t ipip_get_size(const struct net_device *dev)
4790974658dSNicolas Dichtel {
4800974658dSNicolas Dichtel 	return
4810974658dSNicolas Dichtel 		/* IFLA_IPTUN_LINK */
4820974658dSNicolas Dichtel 		nla_total_size(4) +
4830974658dSNicolas Dichtel 		/* IFLA_IPTUN_LOCAL */
4840974658dSNicolas Dichtel 		nla_total_size(4) +
4850974658dSNicolas Dichtel 		/* IFLA_IPTUN_REMOTE */
4860974658dSNicolas Dichtel 		nla_total_size(4) +
4870974658dSNicolas Dichtel 		/* IFLA_IPTUN_TTL */
4880974658dSNicolas Dichtel 		nla_total_size(1) +
4890974658dSNicolas Dichtel 		/* IFLA_IPTUN_TOS */
4900974658dSNicolas Dichtel 		nla_total_size(1) +
4911b69e7e6SSimon Horman 		/* IFLA_IPTUN_PROTO */
4921b69e7e6SSimon Horman 		nla_total_size(1) +
493befe2aa1SNicolas Dichtel 		/* IFLA_IPTUN_PMTUDISC */
494befe2aa1SNicolas Dichtel 		nla_total_size(1) +
495473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_TYPE */
496473ab820STom Herbert 		nla_total_size(2) +
497473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_FLAGS */
498473ab820STom Herbert 		nla_total_size(2) +
499473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_SPORT */
500473ab820STom Herbert 		nla_total_size(2) +
501473ab820STom Herbert 		/* IFLA_IPTUN_ENCAP_DPORT */
502473ab820STom Herbert 		nla_total_size(2) +
503cfc7381bSAlexei Starovoitov 		/* IFLA_IPTUN_COLLECT_METADATA */
504cfc7381bSAlexei Starovoitov 		nla_total_size(0) +
5059830ad4cSCraig Gallek 		/* IFLA_IPTUN_FWMARK */
5069830ad4cSCraig Gallek 		nla_total_size(4) +
5070974658dSNicolas Dichtel 		0;
5080974658dSNicolas Dichtel }
5090974658dSNicolas Dichtel 
5100974658dSNicolas Dichtel static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
5110974658dSNicolas Dichtel {
5120974658dSNicolas Dichtel 	struct ip_tunnel *tunnel = netdev_priv(dev);
5130974658dSNicolas Dichtel 	struct ip_tunnel_parm *parm = &tunnel->parms;
5140974658dSNicolas Dichtel 
5150974658dSNicolas Dichtel 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
516930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
517930345eaSJiri Benc 	    nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
5180974658dSNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
519befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
5201b69e7e6SSimon Horman 	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
521befe2aa1SNicolas Dichtel 	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
5229830ad4cSCraig Gallek 		       !!(parm->iph.frag_off & htons(IP_DF))) ||
5239830ad4cSCraig Gallek 	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
5240974658dSNicolas Dichtel 		goto nla_put_failure;
525473ab820STom Herbert 
526473ab820STom Herbert 	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
527473ab820STom Herbert 			tunnel->encap.type) ||
5283e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
529473ab820STom Herbert 			 tunnel->encap.sport) ||
5303e97fa70SSabrina Dubroca 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
531473ab820STom Herbert 			 tunnel->encap.dport) ||
532473ab820STom Herbert 	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
533e1b2cb65STom Herbert 			tunnel->encap.flags))
534473ab820STom Herbert 		goto nla_put_failure;
535473ab820STom Herbert 
536cfc7381bSAlexei Starovoitov 	if (tunnel->collect_md)
537cfc7381bSAlexei Starovoitov 		if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
538cfc7381bSAlexei Starovoitov 			goto nla_put_failure;
5390974658dSNicolas Dichtel 	return 0;
5400974658dSNicolas Dichtel 
5410974658dSNicolas Dichtel nla_put_failure:
5420974658dSNicolas Dichtel 	return -EMSGSIZE;
5430974658dSNicolas Dichtel }
5440974658dSNicolas Dichtel 
545be42da0eSNicolas Dichtel static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
546be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
547be42da0eSNicolas Dichtel 	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
548be42da0eSNicolas Dichtel 	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
549be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
550be42da0eSNicolas Dichtel 	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
5511b69e7e6SSimon Horman 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
552be42da0eSNicolas Dichtel 	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
553473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
554473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
555473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
556473ab820STom Herbert 	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
557cfc7381bSAlexei Starovoitov 	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
5589830ad4cSCraig Gallek 	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
559be42da0eSNicolas Dichtel };
560be42da0eSNicolas Dichtel 
5610974658dSNicolas Dichtel static struct rtnl_link_ops ipip_link_ops __read_mostly = {
5620974658dSNicolas Dichtel 	.kind		= "ipip",
5630974658dSNicolas Dichtel 	.maxtype	= IFLA_IPTUN_MAX,
564be42da0eSNicolas Dichtel 	.policy		= ipip_policy,
5650974658dSNicolas Dichtel 	.priv_size	= sizeof(struct ip_tunnel),
566be42da0eSNicolas Dichtel 	.setup		= ipip_tunnel_setup,
5671b69e7e6SSimon Horman 	.validate	= ipip_tunnel_validate,
568be42da0eSNicolas Dichtel 	.newlink	= ipip_newlink,
569be42da0eSNicolas Dichtel 	.changelink	= ipip_changelink,
570fd58156eSPravin B Shelar 	.dellink	= ip_tunnel_dellink,
5710974658dSNicolas Dichtel 	.get_size	= ipip_get_size,
5720974658dSNicolas Dichtel 	.fill_info	= ipip_fill_info,
5731728d4faSNicolas Dichtel 	.get_link_net	= ip_tunnel_get_link_net,
5740974658dSNicolas Dichtel };
5750974658dSNicolas Dichtel 
5766dcd814bSEric Dumazet static struct xfrm_tunnel ipip_handler __read_mostly = {
5771da177e4SLinus Torvalds 	.handler	=	ipip_rcv,
5781da177e4SLinus Torvalds 	.err_handler	=	ipip_err,
579d2acc347SHerbert Xu 	.priority	=	1,
5801da177e4SLinus Torvalds };
5811da177e4SLinus Torvalds 
5821b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
5831b69e7e6SSimon Horman static struct xfrm_tunnel mplsip_handler __read_mostly = {
5841b69e7e6SSimon Horman 	.handler	=	mplsip_rcv,
5851b69e7e6SSimon Horman 	.err_handler	=	ipip_err,
5861b69e7e6SSimon Horman 	.priority	=	1,
5871b69e7e6SSimon Horman };
5881b69e7e6SSimon Horman #endif
5891b69e7e6SSimon Horman 
5902c8c1e72SAlexey Dobriyan static int __net_init ipip_init_net(struct net *net)
59110dc4c7bSPavel Emelyanov {
592fd58156eSPravin B Shelar 	return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
59310dc4c7bSPavel Emelyanov }
59410dc4c7bSPavel Emelyanov 
59564bc1781SEric Dumazet static void __net_exit ipip_exit_batch_net(struct list_head *list_net)
59610dc4c7bSPavel Emelyanov {
59764bc1781SEric Dumazet 	ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops);
59810dc4c7bSPavel Emelyanov }
59910dc4c7bSPavel Emelyanov 
60010dc4c7bSPavel Emelyanov static struct pernet_operations ipip_net_ops = {
60110dc4c7bSPavel Emelyanov 	.init = ipip_init_net,
60264bc1781SEric Dumazet 	.exit_batch = ipip_exit_batch_net,
60386de8a63SEric W. Biederman 	.id   = &ipip_net_id,
604fd58156eSPravin B Shelar 	.size = sizeof(struct ip_tunnel_net),
60510dc4c7bSPavel Emelyanov };
60610dc4c7bSPavel Emelyanov 
6071da177e4SLinus Torvalds static int __init ipip_init(void)
6081da177e4SLinus Torvalds {
6091da177e4SLinus Torvalds 	int err;
6101da177e4SLinus Torvalds 
6111b69e7e6SSimon Horman 	pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
6121da177e4SLinus Torvalds 
61386de8a63SEric W. Biederman 	err = register_pernet_device(&ipip_net_ops);
614d5aa407fSAlexey Dobriyan 	if (err < 0)
615d5aa407fSAlexey Dobriyan 		return err;
616d5aa407fSAlexey Dobriyan 	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
617d5aa407fSAlexey Dobriyan 	if (err < 0) {
618058bd4d2SJoe Perches 		pr_info("%s: can't register tunnel\n", __func__);
6191b69e7e6SSimon Horman 		goto xfrm_tunnel_ipip_failed;
620d5aa407fSAlexey Dobriyan 	}
6211b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6221b69e7e6SSimon Horman 	err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
6231b69e7e6SSimon Horman 	if (err < 0) {
6241b69e7e6SSimon Horman 		pr_info("%s: can't register tunnel\n", __func__);
6251b69e7e6SSimon Horman 		goto xfrm_tunnel_mplsip_failed;
6261b69e7e6SSimon Horman 	}
6271b69e7e6SSimon Horman #endif
6280974658dSNicolas Dichtel 	err = rtnl_link_register(&ipip_link_ops);
6290974658dSNicolas Dichtel 	if (err < 0)
6300974658dSNicolas Dichtel 		goto rtnl_link_failed;
6310974658dSNicolas Dichtel 
6320974658dSNicolas Dichtel out:
633b9855c54SPavel Emelyanov 	return err;
6340974658dSNicolas Dichtel 
6350974658dSNicolas Dichtel rtnl_link_failed:
6361b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
63757ebc8f0SVadim Fedorenko 	xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
6381b69e7e6SSimon Horman xfrm_tunnel_mplsip_failed:
6391b69e7e6SSimon Horman 
6401b69e7e6SSimon Horman #endif
6410974658dSNicolas Dichtel 	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
6421b69e7e6SSimon Horman xfrm_tunnel_ipip_failed:
6430974658dSNicolas Dichtel 	unregister_pernet_device(&ipip_net_ops);
6440974658dSNicolas Dichtel 	goto out;
6451da177e4SLinus Torvalds }
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds static void __exit ipip_fini(void)
6481da177e4SLinus Torvalds {
6490974658dSNicolas Dichtel 	rtnl_link_unregister(&ipip_link_ops);
650c0d56408SKazunori MIYAZAWA 	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
651058bd4d2SJoe Perches 		pr_info("%s: can't deregister tunnel\n", __func__);
6521b69e7e6SSimon Horman #if IS_ENABLED(CONFIG_MPLS)
6531b69e7e6SSimon Horman 	if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
6541b69e7e6SSimon Horman 		pr_info("%s: can't deregister tunnel\n", __func__);
6551b69e7e6SSimon Horman #endif
65686de8a63SEric W. Biederman 	unregister_pernet_device(&ipip_net_ops);
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds module_init(ipip_init);
6601da177e4SLinus Torvalds module_exit(ipip_fini);
6611da177e4SLinus Torvalds MODULE_LICENSE("GPL");
662f98f89a0STom Gundersen MODULE_ALIAS_RTNL_LINK("ipip");
6638909c9adSVasiliy Kulikov MODULE_ALIAS_NETDEV("tunl0");
664