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