18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _NET_IP6_TUNNEL_H
38c2ecf20Sopenharmony_ci#define _NET_IP6_TUNNEL_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
68c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
78c2ecf20Sopenharmony_ci#include <linux/if_tunnel.h>
88c2ecf20Sopenharmony_ci#include <linux/ip6_tunnel.h>
98c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h>
108c2ecf20Sopenharmony_ci#include <net/dst_cache.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define IP6TUNNEL_ERR_TIMEO (30*HZ)
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* capable of sending packets */
158c2ecf20Sopenharmony_ci#define IP6_TNL_F_CAP_XMIT 0x10000
168c2ecf20Sopenharmony_ci/* capable of receiving packets */
178c2ecf20Sopenharmony_ci#define IP6_TNL_F_CAP_RCV 0x20000
188c2ecf20Sopenharmony_ci/* determine capability on a per-packet basis */
198c2ecf20Sopenharmony_ci#define IP6_TNL_F_CAP_PER_PACKET 0x40000
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct __ip6_tnl_parm {
228c2ecf20Sopenharmony_ci	char name[IFNAMSIZ];	/* name of tunnel device */
238c2ecf20Sopenharmony_ci	int link;		/* ifindex of underlying L2 interface */
248c2ecf20Sopenharmony_ci	__u8 proto;		/* tunnel protocol */
258c2ecf20Sopenharmony_ci	__u8 encap_limit;	/* encapsulation limit for tunnel */
268c2ecf20Sopenharmony_ci	__u8 hop_limit;		/* hop limit for tunnel */
278c2ecf20Sopenharmony_ci	bool collect_md;
288c2ecf20Sopenharmony_ci	__be32 flowinfo;	/* traffic class and flowlabel for tunnel */
298c2ecf20Sopenharmony_ci	__u32 flags;		/* tunnel flags */
308c2ecf20Sopenharmony_ci	struct in6_addr laddr;	/* local tunnel end-point address */
318c2ecf20Sopenharmony_ci	struct in6_addr raddr;	/* remote tunnel end-point address */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	__be16			i_flags;
348c2ecf20Sopenharmony_ci	__be16			o_flags;
358c2ecf20Sopenharmony_ci	__be32			i_key;
368c2ecf20Sopenharmony_ci	__be32			o_key;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	__u32			fwmark;
398c2ecf20Sopenharmony_ci	__u32			index;	/* ERSPAN type II index */
408c2ecf20Sopenharmony_ci	__u8			erspan_ver;	/* ERSPAN version */
418c2ecf20Sopenharmony_ci	__u8			dir;	/* direction */
428c2ecf20Sopenharmony_ci	__u16			hwid;	/* hwid */
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* IPv6 tunnel */
468c2ecf20Sopenharmony_cistruct ip6_tnl {
478c2ecf20Sopenharmony_ci	struct ip6_tnl __rcu *next;	/* next tunnel in list */
488c2ecf20Sopenharmony_ci	struct net_device *dev;	/* virtual device associated with tunnel */
498c2ecf20Sopenharmony_ci	struct net *net;	/* netns for packet i/o */
508c2ecf20Sopenharmony_ci	struct __ip6_tnl_parm parms;	/* tunnel configuration parameters */
518c2ecf20Sopenharmony_ci	struct flowi fl;	/* flowi template for xmit */
528c2ecf20Sopenharmony_ci	struct dst_cache dst_cache;	/* cached dst */
538c2ecf20Sopenharmony_ci	struct gro_cells gro_cells;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	int err_count;
568c2ecf20Sopenharmony_ci	unsigned long err_time;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* These fields used only by GRE */
598c2ecf20Sopenharmony_ci	__u32 i_seqno;	/* The last seen seqno	*/
608c2ecf20Sopenharmony_ci	atomic_t o_seqno;	/* The last output seqno */
618c2ecf20Sopenharmony_ci	int hlen;       /* tun_hlen + encap_hlen */
628c2ecf20Sopenharmony_ci	int tun_hlen;	/* Precalculated header length */
638c2ecf20Sopenharmony_ci	int encap_hlen; /* Encap header length (FOU,GUE) */
648c2ecf20Sopenharmony_ci	struct ip_tunnel_encap encap;
658c2ecf20Sopenharmony_ci	int mlink;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct ip6_tnl_encap_ops {
698c2ecf20Sopenharmony_ci	size_t (*encap_hlen)(struct ip_tunnel_encap *e);
708c2ecf20Sopenharmony_ci	int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e,
718c2ecf20Sopenharmony_ci			    u8 *protocol, struct flowi6 *fl6);
728c2ecf20Sopenharmony_ci	int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
738c2ecf20Sopenharmony_ci			   u8 type, u8 code, int offset, __be32 info);
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#ifdef CONFIG_INET
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciextern const struct ip6_tnl_encap_ops __rcu *
798c2ecf20Sopenharmony_ci		ip6tun_encaps[MAX_IPTUN_ENCAP_OPS];
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops,
828c2ecf20Sopenharmony_ci			  unsigned int num);
838c2ecf20Sopenharmony_ciint ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops,
848c2ecf20Sopenharmony_ci			  unsigned int num);
858c2ecf20Sopenharmony_ciint ip6_tnl_encap_setup(struct ip6_tnl *t,
868c2ecf20Sopenharmony_ci			struct ip_tunnel_encap *ipencap);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic inline int ip6_encap_hlen(struct ip_tunnel_encap *e)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	const struct ip6_tnl_encap_ops *ops;
918c2ecf20Sopenharmony_ci	int hlen = -EINVAL;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (e->type == TUNNEL_ENCAP_NONE)
948c2ecf20Sopenharmony_ci		return 0;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (e->type >= MAX_IPTUN_ENCAP_OPS)
978c2ecf20Sopenharmony_ci		return -EINVAL;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	rcu_read_lock();
1008c2ecf20Sopenharmony_ci	ops = rcu_dereference(ip6tun_encaps[e->type]);
1018c2ecf20Sopenharmony_ci	if (likely(ops && ops->encap_hlen))
1028c2ecf20Sopenharmony_ci		hlen = ops->encap_hlen(e);
1038c2ecf20Sopenharmony_ci	rcu_read_unlock();
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return hlen;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic inline int ip6_tnl_encap(struct sk_buff *skb, struct ip6_tnl *t,
1098c2ecf20Sopenharmony_ci				u8 *protocol, struct flowi6 *fl6)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	const struct ip6_tnl_encap_ops *ops;
1128c2ecf20Sopenharmony_ci	int ret = -EINVAL;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (t->encap.type == TUNNEL_ENCAP_NONE)
1158c2ecf20Sopenharmony_ci		return 0;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (t->encap.type >= MAX_IPTUN_ENCAP_OPS)
1188c2ecf20Sopenharmony_ci		return -EINVAL;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	rcu_read_lock();
1218c2ecf20Sopenharmony_ci	ops = rcu_dereference(ip6tun_encaps[t->encap.type]);
1228c2ecf20Sopenharmony_ci	if (likely(ops && ops->build_header))
1238c2ecf20Sopenharmony_ci		ret = ops->build_header(skb, &t->encap, protocol, fl6);
1248c2ecf20Sopenharmony_ci	rcu_read_unlock();
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return ret;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* Tunnel encapsulation limit destination sub-option */
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistruct ipv6_tlv_tnl_enc_lim {
1328c2ecf20Sopenharmony_ci	__u8 type;		/* type-code for option         */
1338c2ecf20Sopenharmony_ci	__u8 length;		/* option length                */
1348c2ecf20Sopenharmony_ci	__u8 encap_limit;	/* tunnel encapsulation limit   */
1358c2ecf20Sopenharmony_ci} __packed;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ciint ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
1388c2ecf20Sopenharmony_ci		const struct in6_addr *raddr);
1398c2ecf20Sopenharmony_ciint ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
1408c2ecf20Sopenharmony_ci		const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
1418c2ecf20Sopenharmony_ci		bool log_ecn_error);
1428c2ecf20Sopenharmony_ciint ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
1438c2ecf20Sopenharmony_ci		     const struct in6_addr *raddr);
1448c2ecf20Sopenharmony_ciint ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
1458c2ecf20Sopenharmony_ci		 struct flowi6 *fl6, int encap_limit, __u32 *pmtu, __u8 proto);
1468c2ecf20Sopenharmony_ci__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
1478c2ecf20Sopenharmony_ci__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
1488c2ecf20Sopenharmony_ci			     const struct in6_addr *raddr);
1498c2ecf20Sopenharmony_cistruct net *ip6_tnl_get_link_net(const struct net_device *dev);
1508c2ecf20Sopenharmony_ciint ip6_tnl_get_iflink(const struct net_device *dev);
1518c2ecf20Sopenharmony_ciint ip6_tnl_change_mtu(struct net_device *dev, int new_mtu);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
1548c2ecf20Sopenharmony_ci				  struct net_device *dev)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	int pkt_len, err;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
1598c2ecf20Sopenharmony_ci	pkt_len = skb->len - skb_inner_network_offset(skb);
1608c2ecf20Sopenharmony_ci	err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (dev) {
1638c2ecf20Sopenharmony_ci		if (unlikely(net_xmit_eval(err)))
1648c2ecf20Sopenharmony_ci			pkt_len = -1;
1658c2ecf20Sopenharmony_ci		iptunnel_xmit_stats(dev, pkt_len);
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci#endif
1698c2ecf20Sopenharmony_ci#endif
170