1380 lines · 38.0 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0-or-later *//* *	Linux INET6 implementation * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt> */ #ifndef _NET_IPV6_H#define _NET_IPV6_H #include <linux/ipv6.h>#include <linux/hardirq.h>#include <linux/jhash.h>#include <linux/refcount.h>#include <linux/jump_label_ratelimit.h>#include <net/if_inet6.h>#include <net/flow.h>#include <net/flow_dissector.h>#include <net/inet_dscp.h>#include <net/snmp.h>#include <net/netns/hash.h> struct ip_tunnel_info; #define SIN6_LEN_RFC2133	24 #define IPV6_MAXPLEN		65535 /* *	NextHeader field of IPv6 header */ #define NEXTHDR_HOP		0	/* Hop-by-hop option header. */#define NEXTHDR_IPV4		4	/* IPv4 in IPv6 */#define NEXTHDR_TCP		6	/* TCP segment. */#define NEXTHDR_UDP		17	/* UDP message. */#define NEXTHDR_IPV6		41	/* IPv6 in IPv6 */#define NEXTHDR_ROUTING		43	/* Routing header. */#define NEXTHDR_FRAGMENT	44	/* Fragmentation/reassembly header. */#define NEXTHDR_GRE		47	/* GRE header. */#define NEXTHDR_ESP		50	/* Encapsulating security payload. */#define NEXTHDR_AUTH		51	/* Authentication header. */#define NEXTHDR_ICMP		58	/* ICMP for IPv6. */#define NEXTHDR_NONE		59	/* No next header */#define NEXTHDR_DEST		60	/* Destination options header. */#define NEXTHDR_SCTP		132	/* SCTP message. */#define NEXTHDR_MOBILITY	135	/* Mobility header. */ #define NEXTHDR_MAX		255 #define IPV6_DEFAULT_HOPLIMIT   64#define IPV6_DEFAULT_MCASTHOPS	1 /* Limits on Hop-by-Hop and Destination options. * * Per RFC8200 there is no limit on the maximum number or lengths of options in * Hop-by-Hop or Destination options other then the packet must fit in an MTU. * We allow configurable limits in order to mitigate potential denial of * service attacks. * * There are three limits that may be set: *   - Limit the number of options in a Hop-by-Hop or Destination options *     extension header *   - Limit the byte length of a Hop-by-Hop or Destination options extension *     header *   - Disallow unknown options * * The limits are expressed in corresponding sysctls: * * ipv6.sysctl.max_dst_opts_cnt * ipv6.sysctl.max_hbh_opts_cnt * ipv6.sysctl.max_dst_opts_len * ipv6.sysctl.max_hbh_opts_len * * max_*_opts_cnt is the number of TLVs that are allowed for Destination * options or Hop-by-Hop options. If the number is less than zero then unknown * TLVs are disallowed and the number of known options that are allowed is the * absolute value. Setting the value to INT_MAX indicates no limit. * * max_*_opts_len is the length limit in bytes of a Destination or * Hop-by-Hop options extension header. Setting the value to INT_MAX * indicates no length limit. * * If a limit is exceeded when processing an extension header the packet is * silently discarded. */ /* Default limits for Hop-by-Hop and Destination options */#define IP6_DEFAULT_MAX_DST_OPTS_CNT	 8#define IP6_DEFAULT_MAX_HBH_OPTS_CNT	 8#define IP6_DEFAULT_MAX_DST_OPTS_LEN	 INT_MAX /* No limit */#define IP6_DEFAULT_MAX_HBH_OPTS_LEN	 INT_MAX /* No limit */ /* *	Addr type *	 *	type	-	unicast | multicast *	scope	-	local	| site	    | global *	v4	-	compat *	v4mapped *	any *	loopback */ #define IPV6_ADDR_ANY		0x0000U #define IPV6_ADDR_UNICAST	0x0001U#define IPV6_ADDR_MULTICAST	0x0002U #define IPV6_ADDR_LOOPBACK	0x0010U#define IPV6_ADDR_LINKLOCAL	0x0020U#define IPV6_ADDR_SITELOCAL	0x0040U #define IPV6_ADDR_COMPATv4	0x0080U #define IPV6_ADDR_SCOPE_MASK	0x00f0U #define IPV6_ADDR_MAPPED	0x1000U /* *	Addr scopes */#define IPV6_ADDR_MC_SCOPE(a)	\	((a)->s6_addr[1] & 0x0f)	/* nonstandard */#define __IPV6_ADDR_SCOPE_INVALID	-1#define IPV6_ADDR_SCOPE_NODELOCAL	0x01#define IPV6_ADDR_SCOPE_LINKLOCAL	0x02#define IPV6_ADDR_SCOPE_SITELOCAL	0x05#define IPV6_ADDR_SCOPE_ORGLOCAL	0x08#define IPV6_ADDR_SCOPE_GLOBAL		0x0e /* *	Addr flags */#define IPV6_ADDR_MC_FLAG_TRANSIENT(a)	\	((a)->s6_addr[1] & 0x10)#define IPV6_ADDR_MC_FLAG_PREFIX(a)	\	((a)->s6_addr[1] & 0x20)#define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a)	\	((a)->s6_addr[1] & 0x40) /* *	fragmentation header */ struct frag_hdr {	__u8	nexthdr;	__u8	reserved;	__be16	frag_off;	__be32	identification;}; /* * Jumbo payload option, as described in RFC 2675 2. */struct hop_jumbo_hdr {	u8	nexthdr;	u8	hdrlen;	u8	tlv_type;	/* IPV6_TLV_JUMBO, 0xC2 */	u8	tlv_len;	/* 4 */	__be32	jumbo_payload_len;}; #define	IP6_MF		0x0001#define	IP6_OFFSET	0xFFF8 struct ip6_fraglist_iter {	struct ipv6hdr	*tmp_hdr;	struct sk_buff	*frag;	int		offset;	unsigned int	hlen;	__be32		frag_id;	u8		nexthdr;}; int ip6_fraglist_init(struct sk_buff *skb, unsigned int hlen, u8 *prevhdr,		      u8 nexthdr, __be32 frag_id,		      struct ip6_fraglist_iter *iter);void ip6_fraglist_prepare(struct sk_buff *skb, struct ip6_fraglist_iter *iter); static inline struct sk_buff *ip6_fraglist_next(struct ip6_fraglist_iter *iter){	struct sk_buff *skb = iter->frag; 	iter->frag = skb->next;	skb_mark_not_on_list(skb); 	return skb;} struct ip6_frag_state {	u8		*prevhdr;	unsigned int	hlen;	unsigned int	mtu;	unsigned int	left;	int		offset;	int		ptr;	int		hroom;	int		troom;	__be32		frag_id;	u8		nexthdr;}; void ip6_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int mtu,		   unsigned short needed_tailroom, int hdr_room, u8 *prevhdr,		   u8 nexthdr, __be32 frag_id, struct ip6_frag_state *state);struct sk_buff *ip6_frag_next(struct sk_buff *skb,			      struct ip6_frag_state *state); #define IP6_REPLY_MARK(net, mark) \	((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0) #include <net/sock.h> /* sysctls */extern int sysctl_mld_max_msf;extern int sysctl_mld_qrv; #define _DEVINC(net, statname, mod, idev, field)			\({									\	struct inet6_dev *_idev = (idev);				\	if (likely(_idev != NULL))					\		mod##SNMP_INC_STATS64((_idev)->stats.statname, (field));\	mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\}) /* per device counters are atomic_long_t */#define _DEVINCATOMIC(net, statname, mod, idev, field)			\({									\	struct inet6_dev *_idev = (idev);				\	if (likely(_idev != NULL))					\		SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \	mod##SNMP_INC_STATS((net)->mib.statname##_statistics, (field));\}) /* per device and per net counters are atomic_long_t */#define _DEVINC_ATOMIC_ATOMIC(net, statname, idev, field)		\({									\	struct inet6_dev *_idev = (idev);				\	if (likely(_idev != NULL))					\		SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \	SNMP_INC_STATS_ATOMIC_LONG((net)->mib.statname##_statistics, (field));\}) #define _DEVADD(net, statname, mod, idev, field, val)			\({									\	struct inet6_dev *_idev = (idev);				\	if (likely(_idev != NULL))					\		mod##SNMP_ADD_STATS((_idev)->stats.statname, (field), (val)); \	mod##SNMP_ADD_STATS((net)->mib.statname##_statistics, (field), (val));\}) #define _DEVUPD(net, statname, mod, idev, field, val)			\({									\	struct inet6_dev *_idev = (idev);				\	if (likely(_idev != NULL))					\		mod##SNMP_UPD_PO_STATS((_idev)->stats.statname, field, (val)); \	mod##SNMP_UPD_PO_STATS((net)->mib.statname##_statistics, field, (val));\}) /* MIBs */ #define IP6_INC_STATS(net, idev,field)		\		_DEVINC(net, ipv6, , idev, field)#define __IP6_INC_STATS(net, idev,field)	\		_DEVINC(net, ipv6, __, idev, field)#define IP6_ADD_STATS(net, idev,field,val)	\		_DEVADD(net, ipv6, , idev, field, val)#define __IP6_ADD_STATS(net, idev,field,val)	\		_DEVADD(net, ipv6, __, idev, field, val)#define IP6_UPD_PO_STATS(net, idev,field,val)   \		_DEVUPD(net, ipv6, , idev, field, val)#define __IP6_UPD_PO_STATS(net, idev,field,val)   \		_DEVUPD(net, ipv6, __, idev, field, val)#define ICMP6_INC_STATS(net, idev, field)	\		_DEVINCATOMIC(net, icmpv6, , idev, field)#define __ICMP6_INC_STATS(net, idev, field)	\		_DEVINCATOMIC(net, icmpv6, __, idev, field) #define ICMP6MSGOUT_INC_STATS(net, idev, field)		\	_DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256)#define ICMP6MSGIN_INC_STATS(net, idev, field)	\	_DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field) struct ip6_ra_chain {	struct ip6_ra_chain	*next;	struct sock		*sk;	int			sel;	void			(*destructor)(struct sock *);}; extern struct ip6_ra_chain	*ip6_ra_chain;extern rwlock_t ip6_ra_lock; /*   This structure is prepared by protocol, when parsing   ancillary data and passed to IPv6. */ struct ipv6_txoptions {	refcount_t		refcnt;	/* Length of this structure */	int			tot_len; 	/* length of extension headers   */ 	__u16			opt_flen;	/* after fragment hdr */	__u16			opt_nflen;	/* before fragment hdr */ 	struct ipv6_opt_hdr	*hopopt;	struct ipv6_opt_hdr	*dst0opt;	struct ipv6_rt_hdr	*srcrt;	/* Routing Header */	struct ipv6_opt_hdr	*dst1opt;	struct rcu_head		rcu;	/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */}; /* flowlabel_reflect sysctl values */enum flowlabel_reflect {	FLOWLABEL_REFLECT_ESTABLISHED		= 1,	FLOWLABEL_REFLECT_TCP_RESET		= 2,	FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES	= 4,}; struct ip6_flowlabel {	struct ip6_flowlabel __rcu *next;	__be32			label;	atomic_t		users;	struct in6_addr		dst;	struct ipv6_txoptions	*opt;	unsigned long		linger;	struct rcu_head		rcu;	u8			share;	union {		struct pid *pid;		kuid_t uid;	} owner;	unsigned long		lastuse;	unsigned long		expires;	struct net		*fl_net;}; #define IPV6_FLOWINFO_MASK		cpu_to_be32(0x0FFFFFFF)#define IPV6_FLOWLABEL_MASK		cpu_to_be32(0x000FFFFF)#define IPV6_FLOWLABEL_STATELESS_FLAG	cpu_to_be32(0x00080000) #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)#define IPV6_TCLASS_SHIFT	20 struct ipv6_fl_socklist {	struct ipv6_fl_socklist	__rcu	*next;	struct ip6_flowlabel		*fl;	struct rcu_head			rcu;}; struct ipcm6_cookie {	struct sockcm_cookie sockc;	__s16 hlimit;	__s16 tclass;	__u16 gso_size;	__s8  dontfrag;	struct ipv6_txoptions *opt;}; static inline void ipcm6_init(struct ipcm6_cookie *ipc6){	*ipc6 = (struct ipcm6_cookie) {		.hlimit = -1,		.tclass = -1,		.dontfrag = -1,	};} static inline void ipcm6_init_sk(struct ipcm6_cookie *ipc6,				 const struct sock *sk){	*ipc6 = (struct ipcm6_cookie) {		.hlimit = -1,		.tclass = inet6_sk(sk)->tclass,		.dontfrag = inet6_test_bit(DONTFRAG, sk),	};} static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np){	struct ipv6_txoptions *opt; 	rcu_read_lock();	opt = rcu_dereference(np->opt);	if (opt) {		if (!refcount_inc_not_zero(&opt->refcnt))			opt = NULL;		else			opt = rcu_pointer_handoff(opt);	}	rcu_read_unlock();	return opt;} static inline void txopt_put(struct ipv6_txoptions *opt){	if (opt && refcount_dec_and_test(&opt->refcnt))		kfree_rcu(opt, rcu);} #if IS_ENABLED(CONFIG_IPV6)struct ip6_flowlabel *__fl6_sock_lookup(struct sock *sk, __be32 label); extern struct static_key_false_deferred ipv6_flowlabel_exclusive;static inline struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk,						    __be32 label){	if (static_branch_unlikely(&ipv6_flowlabel_exclusive.key) &&	    READ_ONCE(sock_net(sk)->ipv6.flowlabel_has_excl))		return __fl6_sock_lookup(sk, label) ? : ERR_PTR(-ENOENT); 	return NULL;}#endif struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,					 struct ip6_flowlabel *fl,					 struct ipv6_txoptions *fopt);void fl6_free_socklist(struct sock *sk);int ipv6_flowlabel_opt(struct sock *sk, sockptr_t optval, int optlen);int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,			   int flags);int ip6_flowlabel_init(void);void ip6_flowlabel_cleanup(void);bool ip6_autoflowlabel(struct net *net, const struct sock *sk); static inline void fl6_sock_release(struct ip6_flowlabel *fl){	if (fl)		atomic_dec(&fl->users);} enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type,				   u8 code, __be32 info); void icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,				struct icmp6hdr *thdr, int len); int ip6_ra_control(struct sock *sk, int sel); int ipv6_parse_hopopts(struct sk_buff *skb); struct ipv6_txoptions *ipv6_dup_options(struct sock *sk,					struct ipv6_txoptions *opt);struct ipv6_txoptions *ipv6_renew_options(struct sock *sk,					  struct ipv6_txoptions *opt,					  int newtype,					  struct ipv6_opt_hdr *newopt);struct ipv6_txoptions *__ipv6_fixup_options(struct ipv6_txoptions *opt_space,					    struct ipv6_txoptions *opt); static inline struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, struct ipv6_txoptions *opt){	if (!opt)		return NULL;	return __ipv6_fixup_options(opt_space, opt);} bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb,		       const struct inet6_skb_parm *opt);struct ipv6_txoptions *ipv6_update_options(struct sock *sk,					   struct ipv6_txoptions *opt); /* This helper is specialized for BIG TCP needs. * It assumes the hop_jumbo_hdr will immediately follow the IPV6 header. * It assumes headers are already in skb->head. * Returns 0, or IPPROTO_TCP if a BIG TCP packet is there. */static inline int ipv6_has_hopopt_jumbo(const struct sk_buff *skb){	const struct hop_jumbo_hdr *jhdr;	const struct ipv6hdr *nhdr; 	if (likely(skb->len <= GRO_LEGACY_MAX_SIZE))		return 0; 	if (skb->protocol != htons(ETH_P_IPV6))		return 0; 	if (skb_network_offset(skb) +	    sizeof(struct ipv6hdr) +	    sizeof(struct hop_jumbo_hdr) > skb_headlen(skb))		return 0; 	nhdr = ipv6_hdr(skb); 	if (nhdr->nexthdr != NEXTHDR_HOP)		return 0; 	jhdr = (const struct hop_jumbo_hdr *) (nhdr + 1);	if (jhdr->tlv_type != IPV6_TLV_JUMBO || jhdr->hdrlen != 0 ||	    jhdr->nexthdr != IPPROTO_TCP)		return 0;

Lines 1–500 of 1380.