1102 lines · 31.2 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 <net/if_inet6.h>#include <net/ndisc.h>#include <net/flow.h>#include <net/flow_dissector.h>#include <net/snmp.h>#include <net/netns/hash.h> #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_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;}; #define	IP6_MF		0x0001#define	IP6_OFFSET	0xFFF8 #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. */}; 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;	__s8  dontfrag;	struct ipv6_txoptions *opt;	__u16 gso_size;}; 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 ipv6_pinfo *np){	*ipc6 = (struct ipcm6_cookie) {		.hlimit = -1,		.tclass = np->tclass,		.dontfrag = np->dontfrag,	};} 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);} struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);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, char __user *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 ipv6_pinfo *np); static inline void fl6_sock_release(struct ip6_flowlabel *fl){	if (fl)		atomic_dec(&fl->users);} void 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); 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); static inline bool ipv6_accept_ra(struct inet6_dev *idev){	/* If forwarding is enabled, RA are not accepted unless the special	 * hybrid mode (accept_ra=2) is enabled.	 */	return idev->cnf.forwarding ? idev->cnf.accept_ra == 2 :	    idev->cnf.accept_ra;} #define IPV6_FRAG_HIGH_THRESH	(4 * 1024*1024)	/* 4194304 */#define IPV6_FRAG_LOW_THRESH	(3 * 1024*1024)	/* 3145728 */#define IPV6_FRAG_TIMEOUT	(60 * HZ)	/* 60 seconds */ int __ipv6_addr_type(const struct in6_addr *addr);static inline int ipv6_addr_type(const struct in6_addr *addr){	return __ipv6_addr_type(addr) & 0xffff;} static inline int ipv6_addr_scope(const struct in6_addr *addr){	return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;} static inline int __ipv6_addr_src_scope(int type){	return (type == IPV6_ADDR_ANY) ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16);} static inline int ipv6_addr_src_scope(const struct in6_addr *addr){	return __ipv6_addr_src_scope(__ipv6_addr_type(addr));} static inline bool __ipv6_addr_needs_scope_id(int type){	return type & IPV6_ADDR_LINKLOCAL ||	       (type & IPV6_ADDR_MULTICAST &&		(type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)));} static inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface){	return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0;} static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2){	return memcmp(a1, a2, sizeof(struct in6_addr));} static inline boolipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m,		     const struct in6_addr *a2){#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64	const unsigned long *ul1 = (const unsigned long *)a1;	const unsigned long *ulm = (const unsigned long *)m;	const unsigned long *ul2 = (const unsigned long *)a2; 	return !!(((ul1[0] ^ ul2[0]) & ulm[0]) |		  ((ul1[1] ^ ul2[1]) & ulm[1]));#else	return !!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) |		  ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) |		  ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) |		  ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3]));#endif} static inline void ipv6_addr_prefix(struct in6_addr *pfx,				    const struct in6_addr *addr,				    int plen){	/* caller must guarantee 0 <= plen <= 128 */	int o = plen >> 3,	    b = plen & 0x7; 	memset(pfx->s6_addr, 0, sizeof(pfx->s6_addr));	memcpy(pfx->s6_addr, addr, o);	if (b != 0)		pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);} static inline void ipv6_addr_prefix_copy(struct in6_addr *addr,					 const struct in6_addr *pfx,					 int plen){	/* caller must guarantee 0 <= plen <= 128 */	int o = plen >> 3,	    b = plen & 0x7; 	memcpy(addr->s6_addr, pfx, o);	if (b != 0) {		addr->s6_addr[o] &= ~(0xff00 >> b);		addr->s6_addr[o] |= (pfx->s6_addr[o] & (0xff00 >> b));	}} static inline void __ipv6_addr_set_half(__be32 *addr,					__be32 wh, __be32 wl){#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64#if defined(__BIG_ENDIAN)	if (__builtin_constant_p(wh) && __builtin_constant_p(wl)) {		*(__force u64 *)addr = ((__force u64)(wh) << 32 | (__force u64)(wl));		return;	}#elif defined(__LITTLE_ENDIAN)	if (__builtin_constant_p(wl) && __builtin_constant_p(wh)) {		*(__force u64 *)addr = ((__force u64)(wl) << 32 | (__force u64)(wh));		return;	}#endif#endif	addr[0] = wh;	addr[1] = wl;}

Lines 1–500 of 1102.