162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	Linux NET3:	IP/IP protocol decoder.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *	Authors:
662306a36Sopenharmony_ci *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *	Fixes:
962306a36Sopenharmony_ci *		Alan Cox	:	Merged and made usable non modular (its so tiny its silly as
1062306a36Sopenharmony_ci *					a module taking up 2 pages).
1162306a36Sopenharmony_ci *		Alan Cox	: 	Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
1262306a36Sopenharmony_ci *					to keep ip_forward happy.
1362306a36Sopenharmony_ci *		Alan Cox	:	More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
1462306a36Sopenharmony_ci *		Kai Schulte	:	Fixed #defines for IP_FIREWALL->FIREWALL
1562306a36Sopenharmony_ci *              David Woodhouse :       Perform some basic ICMP handling.
1662306a36Sopenharmony_ci *                                      IPIP Routing without decapsulation.
1762306a36Sopenharmony_ci *              Carlos Picoto   :       GRE over IP support
1862306a36Sopenharmony_ci *		Alexey Kuznetsov:	Reworked. Really, now it is truncated version of ipv4/ip_gre.c.
1962306a36Sopenharmony_ci *					I do not want to merge them together.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* tunnel.c: an IP tunnel driver
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	The purpose of this driver is to provide an IP tunnel through
2562306a36Sopenharmony_ci	which you can tunnel network traffic transparently across subnets.
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	This was written by looking at Nick Holloway's dummy driver
2862306a36Sopenharmony_ci	Thanks for the great code!
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci		-Sam Lantinga	(slouken@cs.ucdavis.edu)  02/01/95
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	Minor tweaks:
3362306a36Sopenharmony_ci		Cleaned up the code a little and added some pre-1.3.0 tweaks.
3462306a36Sopenharmony_ci		dev->hard_header/hard_header_len changed to use no headers.
3562306a36Sopenharmony_ci		Comments/bracketing tweaked.
3662306a36Sopenharmony_ci		Made the tunnels use dev->name not tunnel: when error reporting.
3762306a36Sopenharmony_ci		Added tx_dropped stat
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci		-Alan Cox	(alan@lxorguk.ukuu.org.uk) 21 March 95
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	Reworked:
4262306a36Sopenharmony_ci		Changed to tunnel to destination gateway in addition to the
4362306a36Sopenharmony_ci			tunnel's pointopoint address
4462306a36Sopenharmony_ci		Almost completely rewritten
4562306a36Sopenharmony_ci		Note:  There is currently no firewall or ICMP handling done.
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		-Sam Lantinga	(slouken@cs.ucdavis.edu) 02/13/96
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci*/
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Things I wish I had known when writing the tunnel driver:
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	When the tunnel_xmit() function is called, the skb contains the
5462306a36Sopenharmony_ci	packet to be sent (plus a great deal of extra info), and dev
5562306a36Sopenharmony_ci	contains the tunnel device that _we_ are.
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	When we are passed a packet, we are expected to fill in the
5862306a36Sopenharmony_ci	source address with our source IP address.
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	What is the proper way to allocate, copy and free a buffer?
6162306a36Sopenharmony_ci	After you allocate it, it is a "0 length" chunk of memory
6262306a36Sopenharmony_ci	starting at zero.  If you want to add headers to the buffer
6362306a36Sopenharmony_ci	later, you'll have to call "skb_reserve(skb, amount)" with
6462306a36Sopenharmony_ci	the amount of memory you want reserved.  Then, you call
6562306a36Sopenharmony_ci	"skb_put(skb, amount)" with the amount of space you want in
6662306a36Sopenharmony_ci	the buffer.  skb_put() returns a pointer to the top (#0) of
6762306a36Sopenharmony_ci	that buffer.  skb->len is set to the amount of space you have
6862306a36Sopenharmony_ci	"allocated" with skb_put().  You can then write up to skb->len
6962306a36Sopenharmony_ci	bytes to that buffer.  If you need more, you can call skb_put()
7062306a36Sopenharmony_ci	again with the additional amount of space you need.  You can
7162306a36Sopenharmony_ci	find out how much more space you can allocate by calling
7262306a36Sopenharmony_ci	"skb_tailroom(skb)".
7362306a36Sopenharmony_ci	Now, to add header space, call "skb_push(skb, header_len)".
7462306a36Sopenharmony_ci	This creates space at the beginning of the buffer and returns
7562306a36Sopenharmony_ci	a pointer to this new space.  If later you need to strip a
7662306a36Sopenharmony_ci	header from a buffer, call "skb_pull(skb, header_len)".
7762306a36Sopenharmony_ci	skb_headroom() will return how much space is left at the top
7862306a36Sopenharmony_ci	of the buffer (before the main data).  Remember, this headroom
7962306a36Sopenharmony_ci	space must be reserved before the skb_put() function is called.
8062306a36Sopenharmony_ci	*/
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci   This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci   For comments look at net/ipv4/ip_gre.c --ANK
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#include <linux/capability.h>
9062306a36Sopenharmony_ci#include <linux/module.h>
9162306a36Sopenharmony_ci#include <linux/types.h>
9262306a36Sopenharmony_ci#include <linux/kernel.h>
9362306a36Sopenharmony_ci#include <linux/slab.h>
9462306a36Sopenharmony_ci#include <linux/uaccess.h>
9562306a36Sopenharmony_ci#include <linux/skbuff.h>
9662306a36Sopenharmony_ci#include <linux/netdevice.h>
9762306a36Sopenharmony_ci#include <linux/in.h>
9862306a36Sopenharmony_ci#include <linux/tcp.h>
9962306a36Sopenharmony_ci#include <linux/udp.h>
10062306a36Sopenharmony_ci#include <linux/if_arp.h>
10162306a36Sopenharmony_ci#include <linux/init.h>
10262306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h>
10362306a36Sopenharmony_ci#include <linux/if_ether.h>
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#include <net/sock.h>
10662306a36Sopenharmony_ci#include <net/ip.h>
10762306a36Sopenharmony_ci#include <net/icmp.h>
10862306a36Sopenharmony_ci#include <net/ip_tunnels.h>
10962306a36Sopenharmony_ci#include <net/inet_ecn.h>
11062306a36Sopenharmony_ci#include <net/xfrm.h>
11162306a36Sopenharmony_ci#include <net/net_namespace.h>
11262306a36Sopenharmony_ci#include <net/netns/generic.h>
11362306a36Sopenharmony_ci#include <net/dst_metadata.h>
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic bool log_ecn_error = true;
11662306a36Sopenharmony_cimodule_param(log_ecn_error, bool, 0644);
11762306a36Sopenharmony_ciMODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic unsigned int ipip_net_id __read_mostly;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int ipip_tunnel_init(struct net_device *dev);
12262306a36Sopenharmony_cistatic struct rtnl_link_ops ipip_link_ops __read_mostly;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int ipip_err(struct sk_buff *skb, u32 info)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	/* All the routers (except for Linux) return only
12762306a36Sopenharmony_ci	 * 8 bytes of packet payload. It means, that precise relaying of
12862306a36Sopenharmony_ci	 * ICMP in the real Internet is absolutely infeasible.
12962306a36Sopenharmony_ci	 */
13062306a36Sopenharmony_ci	struct net *net = dev_net(skb->dev);
13162306a36Sopenharmony_ci	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
13262306a36Sopenharmony_ci	const struct iphdr *iph = (const struct iphdr *)skb->data;
13362306a36Sopenharmony_ci	const int type = icmp_hdr(skb)->type;
13462306a36Sopenharmony_ci	const int code = icmp_hdr(skb)->code;
13562306a36Sopenharmony_ci	struct ip_tunnel *t;
13662306a36Sopenharmony_ci	int err = 0;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
13962306a36Sopenharmony_ci			     iph->daddr, iph->saddr, 0);
14062306a36Sopenharmony_ci	if (!t) {
14162306a36Sopenharmony_ci		err = -ENOENT;
14262306a36Sopenharmony_ci		goto out;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	switch (type) {
14662306a36Sopenharmony_ci	case ICMP_DEST_UNREACH:
14762306a36Sopenharmony_ci		switch (code) {
14862306a36Sopenharmony_ci		case ICMP_SR_FAILED:
14962306a36Sopenharmony_ci			/* Impossible event. */
15062306a36Sopenharmony_ci			goto out;
15162306a36Sopenharmony_ci		default:
15262306a36Sopenharmony_ci			/* All others are translated to HOST_UNREACH.
15362306a36Sopenharmony_ci			 * rfc2003 contains "deep thoughts" about NET_UNREACH,
15462306a36Sopenharmony_ci			 * I believe they are just ether pollution. --ANK
15562306a36Sopenharmony_ci			 */
15662306a36Sopenharmony_ci			break;
15762306a36Sopenharmony_ci		}
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	case ICMP_TIME_EXCEEDED:
16162306a36Sopenharmony_ci		if (code != ICMP_EXC_TTL)
16262306a36Sopenharmony_ci			goto out;
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	case ICMP_REDIRECT:
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	default:
16962306a36Sopenharmony_ci		goto out;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
17362306a36Sopenharmony_ci		ipv4_update_pmtu(skb, net, info, t->parms.link, iph->protocol);
17462306a36Sopenharmony_ci		goto out;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (type == ICMP_REDIRECT) {
17862306a36Sopenharmony_ci		ipv4_redirect(skb, net, t->parms.link, iph->protocol);
17962306a36Sopenharmony_ci		goto out;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (t->parms.iph.daddr == 0) {
18362306a36Sopenharmony_ci		err = -ENOENT;
18462306a36Sopenharmony_ci		goto out;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
18862306a36Sopenharmony_ci		goto out;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
19162306a36Sopenharmony_ci		t->err_count++;
19262306a36Sopenharmony_ci	else
19362306a36Sopenharmony_ci		t->err_count = 1;
19462306a36Sopenharmony_ci	t->err_time = jiffies;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ciout:
19762306a36Sopenharmony_ci	return err;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const struct tnl_ptk_info ipip_tpi = {
20162306a36Sopenharmony_ci	/* no tunnel info required for ipip. */
20262306a36Sopenharmony_ci	.proto = htons(ETH_P_IP),
20362306a36Sopenharmony_ci};
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
20662306a36Sopenharmony_cistatic const struct tnl_ptk_info mplsip_tpi = {
20762306a36Sopenharmony_ci	/* no tunnel info required for mplsip. */
20862306a36Sopenharmony_ci	.proto = htons(ETH_P_MPLS_UC),
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci#endif
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct net *net = dev_net(skb->dev);
21562306a36Sopenharmony_ci	struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
21662306a36Sopenharmony_ci	struct metadata_dst *tun_dst = NULL;
21762306a36Sopenharmony_ci	struct ip_tunnel *tunnel;
21862306a36Sopenharmony_ci	const struct iphdr *iph;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	iph = ip_hdr(skb);
22162306a36Sopenharmony_ci	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
22262306a36Sopenharmony_ci			iph->saddr, iph->daddr, 0);
22362306a36Sopenharmony_ci	if (tunnel) {
22462306a36Sopenharmony_ci		const struct tnl_ptk_info *tpi;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		if (tunnel->parms.iph.protocol != ipproto &&
22762306a36Sopenharmony_ci		    tunnel->parms.iph.protocol != 0)
22862306a36Sopenharmony_ci			goto drop;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
23162306a36Sopenharmony_ci			goto drop;
23262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
23362306a36Sopenharmony_ci		if (ipproto == IPPROTO_MPLS)
23462306a36Sopenharmony_ci			tpi = &mplsip_tpi;
23562306a36Sopenharmony_ci		else
23662306a36Sopenharmony_ci#endif
23762306a36Sopenharmony_ci			tpi = &ipip_tpi;
23862306a36Sopenharmony_ci		if (iptunnel_pull_header(skb, 0, tpi->proto, false))
23962306a36Sopenharmony_ci			goto drop;
24062306a36Sopenharmony_ci		if (tunnel->collect_md) {
24162306a36Sopenharmony_ci			tun_dst = ip_tun_rx_dst(skb, 0, 0, 0);
24262306a36Sopenharmony_ci			if (!tun_dst)
24362306a36Sopenharmony_ci				return 0;
24462306a36Sopenharmony_ci			ip_tunnel_md_udp_encap(skb, &tun_dst->u.tun_info);
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci		skb_reset_mac_header(skb);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		return ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return -1;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cidrop:
25462306a36Sopenharmony_ci	kfree_skb(skb);
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic int ipip_rcv(struct sk_buff *skb)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
26462306a36Sopenharmony_cistatic int mplsip_rcv(struct sk_buff *skb)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci#endif
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci *	This function assumes it is being called from dev_queue_xmit()
27262306a36Sopenharmony_ci *	and that skb is filled properly by that function.
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistatic netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
27562306a36Sopenharmony_ci				    struct net_device *dev)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct ip_tunnel *tunnel = netdev_priv(dev);
27862306a36Sopenharmony_ci	const struct iphdr  *tiph = &tunnel->parms.iph;
27962306a36Sopenharmony_ci	u8 ipproto;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (!pskb_inet_may_pull(skb))
28262306a36Sopenharmony_ci		goto tx_error;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	switch (skb->protocol) {
28562306a36Sopenharmony_ci	case htons(ETH_P_IP):
28662306a36Sopenharmony_ci		ipproto = IPPROTO_IPIP;
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
28962306a36Sopenharmony_ci	case htons(ETH_P_MPLS_UC):
29062306a36Sopenharmony_ci		ipproto = IPPROTO_MPLS;
29162306a36Sopenharmony_ci		break;
29262306a36Sopenharmony_ci#endif
29362306a36Sopenharmony_ci	default:
29462306a36Sopenharmony_ci		goto tx_error;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (tiph->protocol != ipproto && tiph->protocol != 0)
29862306a36Sopenharmony_ci		goto tx_error;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
30162306a36Sopenharmony_ci		goto tx_error;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	skb_set_inner_ipproto(skb, ipproto);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (tunnel->collect_md)
30662306a36Sopenharmony_ci		ip_md_tunnel_xmit(skb, dev, ipproto, 0);
30762306a36Sopenharmony_ci	else
30862306a36Sopenharmony_ci		ip_tunnel_xmit(skb, dev, tiph, ipproto);
30962306a36Sopenharmony_ci	return NETDEV_TX_OK;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_citx_error:
31262306a36Sopenharmony_ci	kfree_skb(skb);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	DEV_STATS_INC(dev, tx_errors);
31562306a36Sopenharmony_ci	return NETDEV_TX_OK;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	switch (ipproto) {
32162306a36Sopenharmony_ci	case 0:
32262306a36Sopenharmony_ci	case IPPROTO_IPIP:
32362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
32462306a36Sopenharmony_ci	case IPPROTO_MPLS:
32562306a36Sopenharmony_ci#endif
32662306a36Sopenharmony_ci		return true;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return false;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int
33362306a36Sopenharmony_ciipip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
33662306a36Sopenharmony_ci		if (p->iph.version != 4 ||
33762306a36Sopenharmony_ci		    !ipip_tunnel_ioctl_verify_protocol(p->iph.protocol) ||
33862306a36Sopenharmony_ci		    p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)))
33962306a36Sopenharmony_ci			return -EINVAL;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	p->i_key = p->o_key = 0;
34362306a36Sopenharmony_ci	p->i_flags = p->o_flags = 0;
34462306a36Sopenharmony_ci	return ip_tunnel_ctl(dev, p, cmd);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic const struct net_device_ops ipip_netdev_ops = {
34862306a36Sopenharmony_ci	.ndo_init       = ipip_tunnel_init,
34962306a36Sopenharmony_ci	.ndo_uninit     = ip_tunnel_uninit,
35062306a36Sopenharmony_ci	.ndo_start_xmit	= ipip_tunnel_xmit,
35162306a36Sopenharmony_ci	.ndo_siocdevprivate = ip_tunnel_siocdevprivate,
35262306a36Sopenharmony_ci	.ndo_change_mtu = ip_tunnel_change_mtu,
35362306a36Sopenharmony_ci	.ndo_get_stats64 = dev_get_tstats64,
35462306a36Sopenharmony_ci	.ndo_get_iflink = ip_tunnel_get_iflink,
35562306a36Sopenharmony_ci	.ndo_tunnel_ctl	= ipip_tunnel_ctl,
35662306a36Sopenharmony_ci};
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci#define IPIP_FEATURES (NETIF_F_SG |		\
35962306a36Sopenharmony_ci		       NETIF_F_FRAGLIST |	\
36062306a36Sopenharmony_ci		       NETIF_F_HIGHDMA |	\
36162306a36Sopenharmony_ci		       NETIF_F_GSO_SOFTWARE |	\
36262306a36Sopenharmony_ci		       NETIF_F_HW_CSUM)
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void ipip_tunnel_setup(struct net_device *dev)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	dev->netdev_ops		= &ipip_netdev_ops;
36762306a36Sopenharmony_ci	dev->header_ops		= &ip_tunnel_header_ops;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	dev->type		= ARPHRD_TUNNEL;
37062306a36Sopenharmony_ci	dev->flags		= IFF_NOARP;
37162306a36Sopenharmony_ci	dev->addr_len		= 4;
37262306a36Sopenharmony_ci	dev->features		|= NETIF_F_LLTX;
37362306a36Sopenharmony_ci	netif_keep_dst(dev);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	dev->features		|= IPIP_FEATURES;
37662306a36Sopenharmony_ci	dev->hw_features	|= IPIP_FEATURES;
37762306a36Sopenharmony_ci	ip_tunnel_setup(dev, ipip_net_id);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int ipip_tunnel_init(struct net_device *dev)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct ip_tunnel *tunnel = netdev_priv(dev);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	__dev_addr_set(dev, &tunnel->parms.iph.saddr, 4);
38562306a36Sopenharmony_ci	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	tunnel->tun_hlen = 0;
38862306a36Sopenharmony_ci	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
38962306a36Sopenharmony_ci	return ip_tunnel_init(dev);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
39362306a36Sopenharmony_ci				struct netlink_ext_ack *extack)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	u8 proto;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (!data || !data[IFLA_IPTUN_PROTO])
39862306a36Sopenharmony_ci		return 0;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
40162306a36Sopenharmony_ci	if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
40262306a36Sopenharmony_ci		return -EINVAL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void ipip_netlink_parms(struct nlattr *data[],
40862306a36Sopenharmony_ci			       struct ip_tunnel_parm *parms, bool *collect_md,
40962306a36Sopenharmony_ci			       __u32 *fwmark)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	memset(parms, 0, sizeof(*parms));
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	parms->iph.version = 4;
41462306a36Sopenharmony_ci	parms->iph.protocol = IPPROTO_IPIP;
41562306a36Sopenharmony_ci	parms->iph.ihl = 5;
41662306a36Sopenharmony_ci	*collect_md = false;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (!data)
41962306a36Sopenharmony_ci		return;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ip_tunnel_netlink_parms(data, parms);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (data[IFLA_IPTUN_COLLECT_METADATA])
42462306a36Sopenharmony_ci		*collect_md = true;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (data[IFLA_IPTUN_FWMARK])
42762306a36Sopenharmony_ci		*fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic int ipip_newlink(struct net *src_net, struct net_device *dev,
43162306a36Sopenharmony_ci			struct nlattr *tb[], struct nlattr *data[],
43262306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct ip_tunnel *t = netdev_priv(dev);
43562306a36Sopenharmony_ci	struct ip_tunnel_parm p;
43662306a36Sopenharmony_ci	struct ip_tunnel_encap ipencap;
43762306a36Sopenharmony_ci	__u32 fwmark = 0;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
44062306a36Sopenharmony_ci		int err = ip_tunnel_encap_setup(t, &ipencap);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		if (err < 0)
44362306a36Sopenharmony_ci			return err;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ipip_netlink_parms(data, &p, &t->collect_md, &fwmark);
44762306a36Sopenharmony_ci	return ip_tunnel_newlink(dev, tb, &p, fwmark);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
45162306a36Sopenharmony_ci			   struct nlattr *data[],
45262306a36Sopenharmony_ci			   struct netlink_ext_ack *extack)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct ip_tunnel *t = netdev_priv(dev);
45562306a36Sopenharmony_ci	struct ip_tunnel_parm p;
45662306a36Sopenharmony_ci	struct ip_tunnel_encap ipencap;
45762306a36Sopenharmony_ci	bool collect_md;
45862306a36Sopenharmony_ci	__u32 fwmark = t->fwmark;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
46162306a36Sopenharmony_ci		int err = ip_tunnel_encap_setup(t, &ipencap);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		if (err < 0)
46462306a36Sopenharmony_ci			return err;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	ipip_netlink_parms(data, &p, &collect_md, &fwmark);
46862306a36Sopenharmony_ci	if (collect_md)
46962306a36Sopenharmony_ci		return -EINVAL;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
47262306a36Sopenharmony_ci	    (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
47362306a36Sopenharmony_ci		return -EINVAL;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return ip_tunnel_changelink(dev, tb, &p, fwmark);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic size_t ipip_get_size(const struct net_device *dev)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	return
48162306a36Sopenharmony_ci		/* IFLA_IPTUN_LINK */
48262306a36Sopenharmony_ci		nla_total_size(4) +
48362306a36Sopenharmony_ci		/* IFLA_IPTUN_LOCAL */
48462306a36Sopenharmony_ci		nla_total_size(4) +
48562306a36Sopenharmony_ci		/* IFLA_IPTUN_REMOTE */
48662306a36Sopenharmony_ci		nla_total_size(4) +
48762306a36Sopenharmony_ci		/* IFLA_IPTUN_TTL */
48862306a36Sopenharmony_ci		nla_total_size(1) +
48962306a36Sopenharmony_ci		/* IFLA_IPTUN_TOS */
49062306a36Sopenharmony_ci		nla_total_size(1) +
49162306a36Sopenharmony_ci		/* IFLA_IPTUN_PROTO */
49262306a36Sopenharmony_ci		nla_total_size(1) +
49362306a36Sopenharmony_ci		/* IFLA_IPTUN_PMTUDISC */
49462306a36Sopenharmony_ci		nla_total_size(1) +
49562306a36Sopenharmony_ci		/* IFLA_IPTUN_ENCAP_TYPE */
49662306a36Sopenharmony_ci		nla_total_size(2) +
49762306a36Sopenharmony_ci		/* IFLA_IPTUN_ENCAP_FLAGS */
49862306a36Sopenharmony_ci		nla_total_size(2) +
49962306a36Sopenharmony_ci		/* IFLA_IPTUN_ENCAP_SPORT */
50062306a36Sopenharmony_ci		nla_total_size(2) +
50162306a36Sopenharmony_ci		/* IFLA_IPTUN_ENCAP_DPORT */
50262306a36Sopenharmony_ci		nla_total_size(2) +
50362306a36Sopenharmony_ci		/* IFLA_IPTUN_COLLECT_METADATA */
50462306a36Sopenharmony_ci		nla_total_size(0) +
50562306a36Sopenharmony_ci		/* IFLA_IPTUN_FWMARK */
50662306a36Sopenharmony_ci		nla_total_size(4) +
50762306a36Sopenharmony_ci		0;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct ip_tunnel *tunnel = netdev_priv(dev);
51362306a36Sopenharmony_ci	struct ip_tunnel_parm *parm = &tunnel->parms;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
51662306a36Sopenharmony_ci	    nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) ||
51762306a36Sopenharmony_ci	    nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
51862306a36Sopenharmony_ci	    nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
51962306a36Sopenharmony_ci	    nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
52062306a36Sopenharmony_ci	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
52162306a36Sopenharmony_ci	    nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
52262306a36Sopenharmony_ci		       !!(parm->iph.frag_off & htons(IP_DF))) ||
52362306a36Sopenharmony_ci	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, tunnel->fwmark))
52462306a36Sopenharmony_ci		goto nla_put_failure;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE,
52762306a36Sopenharmony_ci			tunnel->encap.type) ||
52862306a36Sopenharmony_ci	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT,
52962306a36Sopenharmony_ci			 tunnel->encap.sport) ||
53062306a36Sopenharmony_ci	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT,
53162306a36Sopenharmony_ci			 tunnel->encap.dport) ||
53262306a36Sopenharmony_ci	    nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS,
53362306a36Sopenharmony_ci			tunnel->encap.flags))
53462306a36Sopenharmony_ci		goto nla_put_failure;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (tunnel->collect_md)
53762306a36Sopenharmony_ci		if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA))
53862306a36Sopenharmony_ci			goto nla_put_failure;
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cinla_put_failure:
54262306a36Sopenharmony_ci	return -EMSGSIZE;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
54662306a36Sopenharmony_ci	[IFLA_IPTUN_LINK]		= { .type = NLA_U32 },
54762306a36Sopenharmony_ci	[IFLA_IPTUN_LOCAL]		= { .type = NLA_U32 },
54862306a36Sopenharmony_ci	[IFLA_IPTUN_REMOTE]		= { .type = NLA_U32 },
54962306a36Sopenharmony_ci	[IFLA_IPTUN_TTL]		= { .type = NLA_U8 },
55062306a36Sopenharmony_ci	[IFLA_IPTUN_TOS]		= { .type = NLA_U8 },
55162306a36Sopenharmony_ci	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
55262306a36Sopenharmony_ci	[IFLA_IPTUN_PMTUDISC]		= { .type = NLA_U8 },
55362306a36Sopenharmony_ci	[IFLA_IPTUN_ENCAP_TYPE]		= { .type = NLA_U16 },
55462306a36Sopenharmony_ci	[IFLA_IPTUN_ENCAP_FLAGS]	= { .type = NLA_U16 },
55562306a36Sopenharmony_ci	[IFLA_IPTUN_ENCAP_SPORT]	= { .type = NLA_U16 },
55662306a36Sopenharmony_ci	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
55762306a36Sopenharmony_ci	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
55862306a36Sopenharmony_ci	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
55962306a36Sopenharmony_ci};
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic struct rtnl_link_ops ipip_link_ops __read_mostly = {
56262306a36Sopenharmony_ci	.kind		= "ipip",
56362306a36Sopenharmony_ci	.maxtype	= IFLA_IPTUN_MAX,
56462306a36Sopenharmony_ci	.policy		= ipip_policy,
56562306a36Sopenharmony_ci	.priv_size	= sizeof(struct ip_tunnel),
56662306a36Sopenharmony_ci	.setup		= ipip_tunnel_setup,
56762306a36Sopenharmony_ci	.validate	= ipip_tunnel_validate,
56862306a36Sopenharmony_ci	.newlink	= ipip_newlink,
56962306a36Sopenharmony_ci	.changelink	= ipip_changelink,
57062306a36Sopenharmony_ci	.dellink	= ip_tunnel_dellink,
57162306a36Sopenharmony_ci	.get_size	= ipip_get_size,
57262306a36Sopenharmony_ci	.fill_info	= ipip_fill_info,
57362306a36Sopenharmony_ci	.get_link_net	= ip_tunnel_get_link_net,
57462306a36Sopenharmony_ci};
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic struct xfrm_tunnel ipip_handler __read_mostly = {
57762306a36Sopenharmony_ci	.handler	=	ipip_rcv,
57862306a36Sopenharmony_ci	.err_handler	=	ipip_err,
57962306a36Sopenharmony_ci	.priority	=	1,
58062306a36Sopenharmony_ci};
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
58362306a36Sopenharmony_cistatic struct xfrm_tunnel mplsip_handler __read_mostly = {
58462306a36Sopenharmony_ci	.handler	=	mplsip_rcv,
58562306a36Sopenharmony_ci	.err_handler	=	ipip_err,
58662306a36Sopenharmony_ci	.priority	=	1,
58762306a36Sopenharmony_ci};
58862306a36Sopenharmony_ci#endif
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic int __net_init ipip_init_net(struct net *net)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void __net_exit ipip_exit_batch_net(struct list_head *list_net)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	ip_tunnel_delete_nets(list_net, ipip_net_id, &ipip_link_ops);
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic struct pernet_operations ipip_net_ops = {
60162306a36Sopenharmony_ci	.init = ipip_init_net,
60262306a36Sopenharmony_ci	.exit_batch = ipip_exit_batch_net,
60362306a36Sopenharmony_ci	.id   = &ipip_net_id,
60462306a36Sopenharmony_ci	.size = sizeof(struct ip_tunnel_net),
60562306a36Sopenharmony_ci};
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int __init ipip_init(void)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	int err;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	err = register_pernet_device(&ipip_net_ops);
61462306a36Sopenharmony_ci	if (err < 0)
61562306a36Sopenharmony_ci		return err;
61662306a36Sopenharmony_ci	err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
61762306a36Sopenharmony_ci	if (err < 0) {
61862306a36Sopenharmony_ci		pr_info("%s: can't register tunnel\n", __func__);
61962306a36Sopenharmony_ci		goto xfrm_tunnel_ipip_failed;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
62262306a36Sopenharmony_ci	err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
62362306a36Sopenharmony_ci	if (err < 0) {
62462306a36Sopenharmony_ci		pr_info("%s: can't register tunnel\n", __func__);
62562306a36Sopenharmony_ci		goto xfrm_tunnel_mplsip_failed;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci#endif
62862306a36Sopenharmony_ci	err = rtnl_link_register(&ipip_link_ops);
62962306a36Sopenharmony_ci	if (err < 0)
63062306a36Sopenharmony_ci		goto rtnl_link_failed;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ciout:
63362306a36Sopenharmony_ci	return err;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cirtnl_link_failed:
63662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
63762306a36Sopenharmony_ci	xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
63862306a36Sopenharmony_cixfrm_tunnel_mplsip_failed:
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci#endif
64162306a36Sopenharmony_ci	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
64262306a36Sopenharmony_cixfrm_tunnel_ipip_failed:
64362306a36Sopenharmony_ci	unregister_pernet_device(&ipip_net_ops);
64462306a36Sopenharmony_ci	goto out;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic void __exit ipip_fini(void)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	rtnl_link_unregister(&ipip_link_ops);
65062306a36Sopenharmony_ci	if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
65162306a36Sopenharmony_ci		pr_info("%s: can't deregister tunnel\n", __func__);
65262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPLS)
65362306a36Sopenharmony_ci	if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
65462306a36Sopenharmony_ci		pr_info("%s: can't deregister tunnel\n", __func__);
65562306a36Sopenharmony_ci#endif
65662306a36Sopenharmony_ci	unregister_pernet_device(&ipip_net_ops);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cimodule_init(ipip_init);
66062306a36Sopenharmony_cimodule_exit(ipip_fini);
66162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
66262306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("ipip");
66362306a36Sopenharmony_ciMODULE_ALIAS_NETDEV("tunl0");
664