162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ADDRCONF_H
362306a36Sopenharmony_ci#define _ADDRCONF_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#define MAX_RTR_SOLICITATIONS		-1		/* unlimited */
662306a36Sopenharmony_ci#define RTR_SOLICITATION_INTERVAL	(4*HZ)
762306a36Sopenharmony_ci#define RTR_SOLICITATION_MAX_INTERVAL	(3600*HZ)	/* 1 hour */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define MIN_VALID_LIFETIME		(2*3600)	/* 2 hours */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define TEMP_VALID_LIFETIME		(7*86400)
1262306a36Sopenharmony_ci#define TEMP_PREFERRED_LIFETIME		(86400)
1362306a36Sopenharmony_ci#define REGEN_MAX_RETRY			(3)
1462306a36Sopenharmony_ci#define MAX_DESYNC_FACTOR		(600)
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define ADDR_CHECK_FREQUENCY		(120*HZ)
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define IPV6_MAX_ADDRESSES		16
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define ADDRCONF_TIMER_FUZZ_MINUS	(HZ > 50 ? HZ / 50 : 1)
2162306a36Sopenharmony_ci#define ADDRCONF_TIMER_FUZZ		(HZ / 4)
2262306a36Sopenharmony_ci#define ADDRCONF_TIMER_FUZZ_MAX		(HZ)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define ADDRCONF_NOTIFY_PRIORITY	0
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/in.h>
2762306a36Sopenharmony_ci#include <linux/in6.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct prefix_info {
3062306a36Sopenharmony_ci	__u8			type;
3162306a36Sopenharmony_ci	__u8			length;
3262306a36Sopenharmony_ci	__u8			prefix_len;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	union __packed {
3562306a36Sopenharmony_ci		__u8		flags;
3662306a36Sopenharmony_ci		struct __packed {
3762306a36Sopenharmony_ci#if defined(__BIG_ENDIAN_BITFIELD)
3862306a36Sopenharmony_ci			__u8	onlink : 1,
3962306a36Sopenharmony_ci			 	autoconf : 1,
4062306a36Sopenharmony_ci				reserved : 6;
4162306a36Sopenharmony_ci#elif defined(__LITTLE_ENDIAN_BITFIELD)
4262306a36Sopenharmony_ci			__u8	reserved : 6,
4362306a36Sopenharmony_ci				autoconf : 1,
4462306a36Sopenharmony_ci				onlink : 1;
4562306a36Sopenharmony_ci#else
4662306a36Sopenharmony_ci#error "Please fix <asm/byteorder.h>"
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci		};
4962306a36Sopenharmony_ci	};
5062306a36Sopenharmony_ci	__be32			valid;
5162306a36Sopenharmony_ci	__be32			prefered;
5262306a36Sopenharmony_ci	__be32			reserved2;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	struct in6_addr		prefix;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* rfc4861 4.6.2: IPv6 PIO is 32 bytes in size */
5862306a36Sopenharmony_cistatic_assert(sizeof(struct prefix_info) == 32);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include <linux/ipv6.h>
6162306a36Sopenharmony_ci#include <linux/netdevice.h>
6262306a36Sopenharmony_ci#include <net/if_inet6.h>
6362306a36Sopenharmony_ci#include <net/ipv6.h>
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct in6_validator_info {
6662306a36Sopenharmony_ci	struct in6_addr		i6vi_addr;
6762306a36Sopenharmony_ci	struct inet6_dev	*i6vi_dev;
6862306a36Sopenharmony_ci	struct netlink_ext_ack	*extack;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct ifa6_config {
7262306a36Sopenharmony_ci	const struct in6_addr	*pfx;
7362306a36Sopenharmony_ci	unsigned int		plen;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	u8			ifa_proto;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	const struct in6_addr	*peer_pfx;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	u32			rt_priority;
8062306a36Sopenharmony_ci	u32			ifa_flags;
8162306a36Sopenharmony_ci	u32			preferred_lft;
8262306a36Sopenharmony_ci	u32			valid_lft;
8362306a36Sopenharmony_ci	u16			scope;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciint addrconf_init(void);
8762306a36Sopenharmony_civoid addrconf_cleanup(void);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ciint addrconf_add_ifaddr(struct net *net, void __user *arg);
9062306a36Sopenharmony_ciint addrconf_del_ifaddr(struct net *net, void __user *arg);
9162306a36Sopenharmony_ciint addrconf_set_dstaddr(struct net *net, void __user *arg);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciint ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
9462306a36Sopenharmony_ci		  const struct net_device *dev, int strict);
9562306a36Sopenharmony_ciint ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
9662306a36Sopenharmony_ci			    const struct net_device *dev, bool skip_dev_check,
9762306a36Sopenharmony_ci			    int strict, u32 banned_flags);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
10062306a36Sopenharmony_ciint ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
10162306a36Sopenharmony_ci#endif
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciint ipv6_chk_rpl_srh_loop(struct net *net, const struct in6_addr *segs,
10462306a36Sopenharmony_ci			  unsigned char nsegs);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cibool ipv6_chk_custom_prefix(const struct in6_addr *addr,
10762306a36Sopenharmony_ci				   const unsigned int prefix_len,
10862306a36Sopenharmony_ci				   struct net_device *dev);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciint ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistruct net_device *ipv6_dev_find(struct net *net, const struct in6_addr *addr,
11362306a36Sopenharmony_ci				 struct net_device *dev);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistruct inet6_ifaddr *ipv6_get_ifaddr(struct net *net,
11662306a36Sopenharmony_ci				     const struct in6_addr *addr,
11762306a36Sopenharmony_ci				     struct net_device *dev, int strict);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ciint ipv6_dev_get_saddr(struct net *net, const struct net_device *dev,
12062306a36Sopenharmony_ci		       const struct in6_addr *daddr, unsigned int srcprefs,
12162306a36Sopenharmony_ci		       struct in6_addr *saddr);
12262306a36Sopenharmony_ciint ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
12362306a36Sopenharmony_ci		    u32 banned_flags);
12462306a36Sopenharmony_cibool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
12562306a36Sopenharmony_ci			  bool match_wildcard);
12662306a36Sopenharmony_cibool inet_rcv_saddr_any(const struct sock *sk);
12762306a36Sopenharmony_civoid addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
12862306a36Sopenharmony_civoid addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_civoid addrconf_add_linklocal(struct inet6_dev *idev,
13162306a36Sopenharmony_ci			    const struct in6_addr *addr, u32 flags);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciint addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
13462306a36Sopenharmony_ci				 const struct prefix_info *pinfo,
13562306a36Sopenharmony_ci				 struct inet6_dev *in6_dev,
13662306a36Sopenharmony_ci				 const struct in6_addr *addr, int addr_type,
13762306a36Sopenharmony_ci				 u32 addr_flags, bool sllao, bool tokenized,
13862306a36Sopenharmony_ci				 __u32 valid_lft, u32 prefered_lft);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic inline void addrconf_addr_eui48_base(u8 *eui, const char *const addr)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	memcpy(eui, addr, 3);
14362306a36Sopenharmony_ci	eui[3] = 0xFF;
14462306a36Sopenharmony_ci	eui[4] = 0xFE;
14562306a36Sopenharmony_ci	memcpy(eui + 5, addr + 3, 3);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic inline void addrconf_addr_eui48(u8 *eui, const char *const addr)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	addrconf_addr_eui48_base(eui, addr);
15162306a36Sopenharmony_ci	eui[0] ^= 2;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	if (dev->addr_len != ETH_ALEN)
15762306a36Sopenharmony_ci		return -1;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/*
16062306a36Sopenharmony_ci	 * The zSeries OSA network cards can be shared among various
16162306a36Sopenharmony_ci	 * OS instances, but the OSA cards have only one MAC address.
16262306a36Sopenharmony_ci	 * This leads to duplicate address conflicts in conjunction
16362306a36Sopenharmony_ci	 * with IPv6 if more than one instance uses the same card.
16462306a36Sopenharmony_ci	 *
16562306a36Sopenharmony_ci	 * The driver for these cards can deliver a unique 16-bit
16662306a36Sopenharmony_ci	 * identifier for each instance sharing the same card.  It is
16762306a36Sopenharmony_ci	 * placed instead of 0xFFFE in the interface identifier.  The
16862306a36Sopenharmony_ci	 * "u" bit of the interface identifier is not inverted in this
16962306a36Sopenharmony_ci	 * case.  Hence the resulting interface identifier has local
17062306a36Sopenharmony_ci	 * scope according to RFC2373.
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	addrconf_addr_eui48_base(eui, dev->dev_addr);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (dev->dev_id) {
17662306a36Sopenharmony_ci		eui[3] = (dev->dev_id >> 8) & 0xFF;
17762306a36Sopenharmony_ci		eui[4] = dev->dev_id & 0xFF;
17862306a36Sopenharmony_ci	} else {
17962306a36Sopenharmony_ci		eui[0] ^= 2;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic inline unsigned long addrconf_timeout_fixup(u32 timeout,
18662306a36Sopenharmony_ci						   unsigned int unit)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	if (timeout == 0xffffffff)
18962306a36Sopenharmony_ci		return ~0UL;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/*
19262306a36Sopenharmony_ci	 * Avoid arithmetic overflow.
19362306a36Sopenharmony_ci	 * Assuming unit is constant and non-zero, this "if" statement
19462306a36Sopenharmony_ci	 * will go away on 64bit archs.
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	if (0xfffffffe > LONG_MAX / unit && timeout > LONG_MAX / unit)
19762306a36Sopenharmony_ci		return LONG_MAX / unit;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return timeout;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline int addrconf_finite_timeout(unsigned long timeout)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	return ~timeout;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/*
20862306a36Sopenharmony_ci *	IPv6 Address Label subsystem (addrlabel.c)
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciint ipv6_addr_label_init(void);
21162306a36Sopenharmony_civoid ipv6_addr_label_cleanup(void);
21262306a36Sopenharmony_ciint ipv6_addr_label_rtnl_register(void);
21362306a36Sopenharmony_ciu32 ipv6_addr_label(struct net *net, const struct in6_addr *addr,
21462306a36Sopenharmony_ci		    int type, int ifindex);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/*
21762306a36Sopenharmony_ci *	multicast prototypes (mcast.c)
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_cistatic inline bool ipv6_mc_may_pull(struct sk_buff *skb,
22062306a36Sopenharmony_ci				    unsigned int len)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
22362306a36Sopenharmony_ci		return false;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return pskb_may_pull(skb, len);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ciint ipv6_sock_mc_join(struct sock *sk, int ifindex,
22962306a36Sopenharmony_ci		      const struct in6_addr *addr);
23062306a36Sopenharmony_ciint ipv6_sock_mc_drop(struct sock *sk, int ifindex,
23162306a36Sopenharmony_ci		      const struct in6_addr *addr);
23262306a36Sopenharmony_civoid __ipv6_sock_mc_close(struct sock *sk);
23362306a36Sopenharmony_civoid ipv6_sock_mc_close(struct sock *sk);
23462306a36Sopenharmony_cibool inet6_mc_check(const struct sock *sk, const struct in6_addr *mc_addr,
23562306a36Sopenharmony_ci		    const struct in6_addr *src_addr);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciint ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr);
23862306a36Sopenharmony_ciint __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr);
23962306a36Sopenharmony_ciint ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr);
24062306a36Sopenharmony_civoid ipv6_mc_up(struct inet6_dev *idev);
24162306a36Sopenharmony_civoid ipv6_mc_down(struct inet6_dev *idev);
24262306a36Sopenharmony_civoid ipv6_mc_unmap(struct inet6_dev *idev);
24362306a36Sopenharmony_civoid ipv6_mc_remap(struct inet6_dev *idev);
24462306a36Sopenharmony_civoid ipv6_mc_init_dev(struct inet6_dev *idev);
24562306a36Sopenharmony_civoid ipv6_mc_destroy_dev(struct inet6_dev *idev);
24662306a36Sopenharmony_ciint ipv6_mc_check_mld(struct sk_buff *skb);
24762306a36Sopenharmony_civoid addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cibool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
25062306a36Sopenharmony_ci			 const struct in6_addr *src_addr);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_civoid ipv6_mc_dad_complete(struct inet6_dev *idev);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/*
25562306a36Sopenharmony_ci * identify MLD packets for MLD filter exceptions
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct icmp6hdr *hdr;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (nexthdr != IPPROTO_ICMPV6 ||
26262306a36Sopenharmony_ci	    !pskb_network_may_pull(skb, offset + sizeof(struct icmp6hdr)))
26362306a36Sopenharmony_ci		return false;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	hdr = (struct icmp6hdr *)(skb_network_header(skb) + offset);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	switch (hdr->icmp6_type) {
26862306a36Sopenharmony_ci	case ICMPV6_MGM_QUERY:
26962306a36Sopenharmony_ci	case ICMPV6_MGM_REPORT:
27062306a36Sopenharmony_ci	case ICMPV6_MGM_REDUCTION:
27162306a36Sopenharmony_ci	case ICMPV6_MLD2_REPORT:
27262306a36Sopenharmony_ci		return true;
27362306a36Sopenharmony_ci	default:
27462306a36Sopenharmony_ci		break;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci	return false;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_civoid addrconf_prefix_rcv(struct net_device *dev,
28062306a36Sopenharmony_ci			 u8 *opt, int len, bool sllao);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/*
28362306a36Sopenharmony_ci *	anycast prototypes (anycast.c)
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_ciint ipv6_sock_ac_join(struct sock *sk, int ifindex,
28662306a36Sopenharmony_ci		      const struct in6_addr *addr);
28762306a36Sopenharmony_ciint ipv6_sock_ac_drop(struct sock *sk, int ifindex,
28862306a36Sopenharmony_ci		      const struct in6_addr *addr);
28962306a36Sopenharmony_civoid __ipv6_sock_ac_close(struct sock *sk);
29062306a36Sopenharmony_civoid ipv6_sock_ac_close(struct sock *sk);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ciint __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr);
29362306a36Sopenharmony_ciint __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr);
29462306a36Sopenharmony_civoid ipv6_ac_destroy_dev(struct inet6_dev *idev);
29562306a36Sopenharmony_cibool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
29662306a36Sopenharmony_ci			 const struct in6_addr *addr);
29762306a36Sopenharmony_cibool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev,
29862306a36Sopenharmony_ci			     const struct in6_addr *addr);
29962306a36Sopenharmony_ciint ipv6_anycast_init(void);
30062306a36Sopenharmony_civoid ipv6_anycast_cleanup(void);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/* Device notifier */
30362306a36Sopenharmony_ciint register_inet6addr_notifier(struct notifier_block *nb);
30462306a36Sopenharmony_ciint unregister_inet6addr_notifier(struct notifier_block *nb);
30562306a36Sopenharmony_ciint inet6addr_notifier_call_chain(unsigned long val, void *v);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciint register_inet6addr_validator_notifier(struct notifier_block *nb);
30862306a36Sopenharmony_ciint unregister_inet6addr_validator_notifier(struct notifier_block *nb);
30962306a36Sopenharmony_ciint inet6addr_validator_notifier_call_chain(unsigned long val, void *v);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_civoid inet6_netconf_notify_devconf(struct net *net, int event, int type,
31262306a36Sopenharmony_ci				  int ifindex, struct ipv6_devconf *devconf);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/**
31562306a36Sopenharmony_ci * __in6_dev_get - get inet6_dev pointer from netdevice
31662306a36Sopenharmony_ci * @dev: network device
31762306a36Sopenharmony_ci *
31862306a36Sopenharmony_ci * Caller must hold rcu_read_lock or RTNL, because this function
31962306a36Sopenharmony_ci * does not take a reference on the inet6_dev.
32062306a36Sopenharmony_ci */
32162306a36Sopenharmony_cistatic inline struct inet6_dev *__in6_dev_get(const struct net_device *dev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	return rcu_dereference_rtnl(dev->ip6_ptr);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/**
32762306a36Sopenharmony_ci * __in6_dev_stats_get - get inet6_dev pointer for stats
32862306a36Sopenharmony_ci * @dev: network device
32962306a36Sopenharmony_ci * @skb: skb for original incoming interface if neeeded
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * Caller must hold rcu_read_lock or RTNL, because this function
33262306a36Sopenharmony_ci * does not take a reference on the inet6_dev.
33362306a36Sopenharmony_ci */
33462306a36Sopenharmony_cistatic inline struct inet6_dev *__in6_dev_stats_get(const struct net_device *dev,
33562306a36Sopenharmony_ci						    const struct sk_buff *skb)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	if (netif_is_l3_master(dev))
33862306a36Sopenharmony_ci		dev = dev_get_by_index_rcu(dev_net(dev), inet6_iif(skb));
33962306a36Sopenharmony_ci	return __in6_dev_get(dev);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci/**
34362306a36Sopenharmony_ci * __in6_dev_get_safely - get inet6_dev pointer from netdevice
34462306a36Sopenharmony_ci * @dev: network device
34562306a36Sopenharmony_ci *
34662306a36Sopenharmony_ci * This is a safer version of __in6_dev_get
34762306a36Sopenharmony_ci */
34862306a36Sopenharmony_cistatic inline struct inet6_dev *__in6_dev_get_safely(const struct net_device *dev)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	if (likely(dev))
35162306a36Sopenharmony_ci		return rcu_dereference_rtnl(dev->ip6_ptr);
35262306a36Sopenharmony_ci	else
35362306a36Sopenharmony_ci		return NULL;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * in6_dev_get - get inet6_dev pointer from netdevice
35862306a36Sopenharmony_ci * @dev: network device
35962306a36Sopenharmony_ci *
36062306a36Sopenharmony_ci * This version can be used in any context, and takes a reference
36162306a36Sopenharmony_ci * on the inet6_dev. Callers must use in6_dev_put() later to
36262306a36Sopenharmony_ci * release this reference.
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_cistatic inline struct inet6_dev *in6_dev_get(const struct net_device *dev)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct inet6_dev *idev;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	rcu_read_lock();
36962306a36Sopenharmony_ci	idev = rcu_dereference(dev->ip6_ptr);
37062306a36Sopenharmony_ci	if (idev)
37162306a36Sopenharmony_ci		refcount_inc(&idev->refcnt);
37262306a36Sopenharmony_ci	rcu_read_unlock();
37362306a36Sopenharmony_ci	return idev;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic inline struct neigh_parms *__in6_dev_nd_parms_get_rcu(const struct net_device *dev)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct inet6_dev *idev = __in6_dev_get(dev);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return idev ? idev->nd_parms : NULL;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_civoid in6_dev_finish_destroy(struct inet6_dev *idev);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic inline void in6_dev_put(struct inet6_dev *idev)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	if (refcount_dec_and_test(&idev->refcnt))
38862306a36Sopenharmony_ci		in6_dev_finish_destroy(idev);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic inline void in6_dev_put_clear(struct inet6_dev **pidev)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct inet6_dev *idev = *pidev;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (idev) {
39662306a36Sopenharmony_ci		in6_dev_put(idev);
39762306a36Sopenharmony_ci		*pidev = NULL;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic inline void __in6_dev_put(struct inet6_dev *idev)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	refcount_dec(&idev->refcnt);
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic inline void in6_dev_hold(struct inet6_dev *idev)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	refcount_inc(&idev->refcnt);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/* called with rcu_read_lock held */
41262306a36Sopenharmony_cistatic inline bool ip6_ignore_linkdown(const struct net_device *dev)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	const struct inet6_dev *idev = __in6_dev_get(dev);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (unlikely(!idev))
41762306a36Sopenharmony_ci		return true;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return !!idev->cnf.ignore_routes_with_linkdown;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_civoid inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic inline void in6_ifa_put(struct inet6_ifaddr *ifp)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	if (refcount_dec_and_test(&ifp->refcnt))
42762306a36Sopenharmony_ci		inet6_ifa_finish_destroy(ifp);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic inline void __in6_ifa_put(struct inet6_ifaddr *ifp)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	refcount_dec(&ifp->refcnt);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic inline void in6_ifa_hold(struct inet6_ifaddr *ifp)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	refcount_inc(&ifp->refcnt);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/*
44262306a36Sopenharmony_ci *	compute link-local solicited-node multicast address
44362306a36Sopenharmony_ci */
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic inline void addrconf_addr_solict_mult(const struct in6_addr *addr,
44662306a36Sopenharmony_ci					     struct in6_addr *solicited)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	ipv6_addr_set(solicited,
44962306a36Sopenharmony_ci		      htonl(0xFF020000), 0,
45062306a36Sopenharmony_ci		      htonl(0x1),
45162306a36Sopenharmony_ci		      htonl(0xFF000000) | addr->s6_addr32[3]);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
45762306a36Sopenharmony_ci	__be64 *p = (__force __be64 *)addr;
45862306a36Sopenharmony_ci	return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(1))) == 0UL;
45962306a36Sopenharmony_ci#else
46062306a36Sopenharmony_ci	return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
46162306a36Sopenharmony_ci		addr->s6_addr32[1] | addr->s6_addr32[2] |
46262306a36Sopenharmony_ci		(addr->s6_addr32[3] ^ htonl(0x00000001))) == 0;
46362306a36Sopenharmony_ci#endif
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic inline bool ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
46962306a36Sopenharmony_ci	__be64 *p = (__force __be64 *)addr;
47062306a36Sopenharmony_ci	return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(2))) == 0UL;
47162306a36Sopenharmony_ci#else
47262306a36Sopenharmony_ci	return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
47362306a36Sopenharmony_ci		addr->s6_addr32[1] | addr->s6_addr32[2] |
47462306a36Sopenharmony_ci		(addr->s6_addr32[3] ^ htonl(0x00000002))) == 0;
47562306a36Sopenharmony_ci#endif
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic inline bool ipv6_addr_is_isatap(const struct in6_addr *addr)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
48662306a36Sopenharmony_ci	__be64 *p = (__force __be64 *)addr;
48762306a36Sopenharmony_ci	return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) |
48862306a36Sopenharmony_ci		((p[1] ^ cpu_to_be64(0x00000001ff000000UL)) &
48962306a36Sopenharmony_ci		 cpu_to_be64(0xffffffffff000000UL))) == 0UL;
49062306a36Sopenharmony_ci#else
49162306a36Sopenharmony_ci	return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
49262306a36Sopenharmony_ci		addr->s6_addr32[1] |
49362306a36Sopenharmony_ci		(addr->s6_addr32[2] ^ htonl(0x00000001)) |
49462306a36Sopenharmony_ci		(addr->s6_addr[12] ^ 0xff)) == 0;
49562306a36Sopenharmony_ci#endif
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic inline bool ipv6_addr_is_all_snoopers(const struct in6_addr *addr)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
50162306a36Sopenharmony_ci	__be64 *p = (__force __be64 *)addr;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) |
50462306a36Sopenharmony_ci		(p[1] ^ cpu_to_be64(0x6a))) == 0UL;
50562306a36Sopenharmony_ci#else
50662306a36Sopenharmony_ci	return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
50762306a36Sopenharmony_ci		addr->s6_addr32[1] | addr->s6_addr32[2] |
50862306a36Sopenharmony_ci		(addr->s6_addr32[3] ^ htonl(0x0000006a))) == 0;
50962306a36Sopenharmony_ci#endif
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
51362306a36Sopenharmony_ciint if6_proc_init(void);
51462306a36Sopenharmony_civoid if6_proc_exit(void);
51562306a36Sopenharmony_ci#endif
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci#endif
518