18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ADDRCONF_H 38c2ecf20Sopenharmony_ci#define _ADDRCONF_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#define MAX_RTR_SOLICITATIONS -1 /* unlimited */ 68c2ecf20Sopenharmony_ci#define RTR_SOLICITATION_INTERVAL (4*HZ) 78c2ecf20Sopenharmony_ci#define RTR_SOLICITATION_MAX_INTERVAL (3600*HZ) /* 1 hour */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define TEMP_VALID_LIFETIME (7*86400) 128c2ecf20Sopenharmony_ci#define TEMP_PREFERRED_LIFETIME (86400) 138c2ecf20Sopenharmony_ci#define REGEN_MAX_RETRY (3) 148c2ecf20Sopenharmony_ci#define MAX_DESYNC_FACTOR (600) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define ADDR_CHECK_FREQUENCY (120*HZ) 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define IPV6_MAX_ADDRESSES 16 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ / 50 : 1) 218c2ecf20Sopenharmony_ci#define ADDRCONF_TIMER_FUZZ (HZ / 4) 228c2ecf20Sopenharmony_ci#define ADDRCONF_TIMER_FUZZ_MAX (HZ) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define ADDRCONF_NOTIFY_PRIORITY 0 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/in.h> 278c2ecf20Sopenharmony_ci#include <linux/in6.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct prefix_info { 308c2ecf20Sopenharmony_ci __u8 type; 318c2ecf20Sopenharmony_ci __u8 length; 328c2ecf20Sopenharmony_ci __u8 prefix_len; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci union __packed { 358c2ecf20Sopenharmony_ci __u8 flags; 368c2ecf20Sopenharmony_ci struct __packed { 378c2ecf20Sopenharmony_ci#if defined(__BIG_ENDIAN_BITFIELD) 388c2ecf20Sopenharmony_ci __u8 onlink : 1, 398c2ecf20Sopenharmony_ci autoconf : 1, 408c2ecf20Sopenharmony_ci reserved : 6; 418c2ecf20Sopenharmony_ci#elif defined(__LITTLE_ENDIAN_BITFIELD) 428c2ecf20Sopenharmony_ci __u8 reserved : 6, 438c2ecf20Sopenharmony_ci autoconf : 1, 448c2ecf20Sopenharmony_ci onlink : 1; 458c2ecf20Sopenharmony_ci#else 468c2ecf20Sopenharmony_ci#error "Please fix <asm/byteorder.h>" 478c2ecf20Sopenharmony_ci#endif 488c2ecf20Sopenharmony_ci }; 498c2ecf20Sopenharmony_ci }; 508c2ecf20Sopenharmony_ci __be32 valid; 518c2ecf20Sopenharmony_ci __be32 prefered; 528c2ecf20Sopenharmony_ci __be32 reserved2; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci struct in6_addr prefix; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* rfc4861 4.6.2: IPv6 PIO is 32 bytes in size */ 588c2ecf20Sopenharmony_cistatic_assert(sizeof(struct prefix_info) == 32); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 618c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 628c2ecf20Sopenharmony_ci#include <net/if_inet6.h> 638c2ecf20Sopenharmony_ci#include <net/ipv6.h> 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct in6_validator_info { 668c2ecf20Sopenharmony_ci struct in6_addr i6vi_addr; 678c2ecf20Sopenharmony_ci struct inet6_dev *i6vi_dev; 688c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct ifa6_config { 728c2ecf20Sopenharmony_ci const struct in6_addr *pfx; 738c2ecf20Sopenharmony_ci unsigned int plen; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci const struct in6_addr *peer_pfx; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci u32 rt_priority; 788c2ecf20Sopenharmony_ci u32 ifa_flags; 798c2ecf20Sopenharmony_ci u32 preferred_lft; 808c2ecf20Sopenharmony_ci u32 valid_lft; 818c2ecf20Sopenharmony_ci u16 scope; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint addrconf_init(void); 858c2ecf20Sopenharmony_civoid addrconf_cleanup(void); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciint addrconf_add_ifaddr(struct net *net, void __user *arg); 888c2ecf20Sopenharmony_ciint addrconf_del_ifaddr(struct net *net, void __user *arg); 898c2ecf20Sopenharmony_ciint addrconf_set_dstaddr(struct net *net, void __user *arg); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ciint ipv6_chk_addr(struct net *net, const struct in6_addr *addr, 928c2ecf20Sopenharmony_ci const struct net_device *dev, int strict); 938c2ecf20Sopenharmony_ciint ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, 948c2ecf20Sopenharmony_ci const struct net_device *dev, bool skip_dev_check, 958c2ecf20Sopenharmony_ci int strict, u32 banned_flags); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 988c2ecf20Sopenharmony_ciint ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciint ipv6_chk_rpl_srh_loop(struct net *net, const struct in6_addr *segs, 1028c2ecf20Sopenharmony_ci unsigned char nsegs); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cibool ipv6_chk_custom_prefix(const struct in6_addr *addr, 1058c2ecf20Sopenharmony_ci const unsigned int prefix_len, 1068c2ecf20Sopenharmony_ci struct net_device *dev); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct net_device *ipv6_dev_find(struct net *net, const struct in6_addr *addr, 1118c2ecf20Sopenharmony_ci struct net_device *dev); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistruct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, 1148c2ecf20Sopenharmony_ci const struct in6_addr *addr, 1158c2ecf20Sopenharmony_ci struct net_device *dev, int strict); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciint ipv6_dev_get_saddr(struct net *net, const struct net_device *dev, 1188c2ecf20Sopenharmony_ci const struct in6_addr *daddr, unsigned int srcprefs, 1198c2ecf20Sopenharmony_ci struct in6_addr *saddr); 1208c2ecf20Sopenharmony_ciint __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, 1218c2ecf20Sopenharmony_ci u32 banned_flags); 1228c2ecf20Sopenharmony_ciint ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, 1238c2ecf20Sopenharmony_ci u32 banned_flags); 1248c2ecf20Sopenharmony_cibool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, 1258c2ecf20Sopenharmony_ci bool match_wildcard); 1268c2ecf20Sopenharmony_cibool inet_rcv_saddr_any(const struct sock *sk); 1278c2ecf20Sopenharmony_civoid addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); 1288c2ecf20Sopenharmony_civoid addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_civoid addrconf_add_linklocal(struct inet6_dev *idev, 1318c2ecf20Sopenharmony_ci const struct in6_addr *addr, u32 flags); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciint addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, 1348c2ecf20Sopenharmony_ci const struct prefix_info *pinfo, 1358c2ecf20Sopenharmony_ci struct inet6_dev *in6_dev, 1368c2ecf20Sopenharmony_ci const struct in6_addr *addr, int addr_type, 1378c2ecf20Sopenharmony_ci u32 addr_flags, bool sllao, bool tokenized, 1388c2ecf20Sopenharmony_ci __u32 valid_lft, u32 prefered_lft); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic inline void addrconf_addr_eui48_base(u8 *eui, const char *const addr) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci memcpy(eui, addr, 3); 1438c2ecf20Sopenharmony_ci eui[3] = 0xFF; 1448c2ecf20Sopenharmony_ci eui[4] = 0xFE; 1458c2ecf20Sopenharmony_ci memcpy(eui + 5, addr + 3, 3); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic inline void addrconf_addr_eui48(u8 *eui, const char *const addr) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci addrconf_addr_eui48_base(eui, addr); 1518c2ecf20Sopenharmony_ci eui[0] ^= 2; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci if (dev->addr_len != ETH_ALEN) 1578c2ecf20Sopenharmony_ci return -1; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* 1608c2ecf20Sopenharmony_ci * The zSeries OSA network cards can be shared among various 1618c2ecf20Sopenharmony_ci * OS instances, but the OSA cards have only one MAC address. 1628c2ecf20Sopenharmony_ci * This leads to duplicate address conflicts in conjunction 1638c2ecf20Sopenharmony_ci * with IPv6 if more than one instance uses the same card. 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * The driver for these cards can deliver a unique 16-bit 1668c2ecf20Sopenharmony_ci * identifier for each instance sharing the same card. It is 1678c2ecf20Sopenharmony_ci * placed instead of 0xFFFE in the interface identifier. The 1688c2ecf20Sopenharmony_ci * "u" bit of the interface identifier is not inverted in this 1698c2ecf20Sopenharmony_ci * case. Hence the resulting interface identifier has local 1708c2ecf20Sopenharmony_ci * scope according to RFC2373. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci addrconf_addr_eui48_base(eui, dev->dev_addr); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (dev->dev_id) { 1768c2ecf20Sopenharmony_ci eui[3] = (dev->dev_id >> 8) & 0xFF; 1778c2ecf20Sopenharmony_ci eui[4] = dev->dev_id & 0xFF; 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci eui[0] ^= 2; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic inline unsigned long addrconf_timeout_fixup(u32 timeout, 1868c2ecf20Sopenharmony_ci unsigned int unit) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci if (timeout == 0xffffffff) 1898c2ecf20Sopenharmony_ci return ~0UL; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* 1928c2ecf20Sopenharmony_ci * Avoid arithmetic overflow. 1938c2ecf20Sopenharmony_ci * Assuming unit is constant and non-zero, this "if" statement 1948c2ecf20Sopenharmony_ci * will go away on 64bit archs. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci if (0xfffffffe > LONG_MAX / unit && timeout > LONG_MAX / unit) 1978c2ecf20Sopenharmony_ci return LONG_MAX / unit; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return timeout; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic inline int addrconf_finite_timeout(unsigned long timeout) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci return ~timeout; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * IPv6 Address Label subsystem (addrlabel.c) 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ciint ipv6_addr_label_init(void); 2118c2ecf20Sopenharmony_civoid ipv6_addr_label_cleanup(void); 2128c2ecf20Sopenharmony_ciint ipv6_addr_label_rtnl_register(void); 2138c2ecf20Sopenharmony_ciu32 ipv6_addr_label(struct net *net, const struct in6_addr *addr, 2148c2ecf20Sopenharmony_ci int type, int ifindex); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * multicast prototypes (mcast.c) 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_cistatic inline bool ipv6_mc_may_pull(struct sk_buff *skb, 2208c2ecf20Sopenharmony_ci unsigned int len) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len) 2238c2ecf20Sopenharmony_ci return false; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return pskb_may_pull(skb, len); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint ipv6_sock_mc_join(struct sock *sk, int ifindex, 2298c2ecf20Sopenharmony_ci const struct in6_addr *addr); 2308c2ecf20Sopenharmony_ciint ipv6_sock_mc_drop(struct sock *sk, int ifindex, 2318c2ecf20Sopenharmony_ci const struct in6_addr *addr); 2328c2ecf20Sopenharmony_civoid __ipv6_sock_mc_close(struct sock *sk); 2338c2ecf20Sopenharmony_civoid ipv6_sock_mc_close(struct sock *sk); 2348c2ecf20Sopenharmony_cibool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, 2358c2ecf20Sopenharmony_ci const struct in6_addr *src_addr); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr); 2388c2ecf20Sopenharmony_ciint __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr); 2398c2ecf20Sopenharmony_ciint ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr); 2408c2ecf20Sopenharmony_civoid ipv6_mc_up(struct inet6_dev *idev); 2418c2ecf20Sopenharmony_civoid ipv6_mc_down(struct inet6_dev *idev); 2428c2ecf20Sopenharmony_civoid ipv6_mc_unmap(struct inet6_dev *idev); 2438c2ecf20Sopenharmony_civoid ipv6_mc_remap(struct inet6_dev *idev); 2448c2ecf20Sopenharmony_civoid ipv6_mc_init_dev(struct inet6_dev *idev); 2458c2ecf20Sopenharmony_civoid ipv6_mc_destroy_dev(struct inet6_dev *idev); 2468c2ecf20Sopenharmony_ciint ipv6_mc_check_mld(struct sk_buff *skb); 2478c2ecf20Sopenharmony_civoid addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cibool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, 2508c2ecf20Sopenharmony_ci const struct in6_addr *src_addr); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_civoid ipv6_mc_dad_complete(struct inet6_dev *idev); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* 2558c2ecf20Sopenharmony_ci * identify MLD packets for MLD filter exceptions 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct icmp6hdr *hdr; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (nexthdr != IPPROTO_ICMPV6 || 2628c2ecf20Sopenharmony_ci !pskb_network_may_pull(skb, offset + sizeof(struct icmp6hdr))) 2638c2ecf20Sopenharmony_ci return false; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci hdr = (struct icmp6hdr *)(skb_network_header(skb) + offset); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci switch (hdr->icmp6_type) { 2688c2ecf20Sopenharmony_ci case ICMPV6_MGM_QUERY: 2698c2ecf20Sopenharmony_ci case ICMPV6_MGM_REPORT: 2708c2ecf20Sopenharmony_ci case ICMPV6_MGM_REDUCTION: 2718c2ecf20Sopenharmony_ci case ICMPV6_MLD2_REPORT: 2728c2ecf20Sopenharmony_ci return true; 2738c2ecf20Sopenharmony_ci default: 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci return false; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_civoid addrconf_prefix_rcv(struct net_device *dev, 2808c2ecf20Sopenharmony_ci u8 *opt, int len, bool sllao); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * anycast prototypes (anycast.c) 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ciint ipv6_sock_ac_join(struct sock *sk, int ifindex, 2868c2ecf20Sopenharmony_ci const struct in6_addr *addr); 2878c2ecf20Sopenharmony_ciint ipv6_sock_ac_drop(struct sock *sk, int ifindex, 2888c2ecf20Sopenharmony_ci const struct in6_addr *addr); 2898c2ecf20Sopenharmony_civoid __ipv6_sock_ac_close(struct sock *sk); 2908c2ecf20Sopenharmony_civoid ipv6_sock_ac_close(struct sock *sk); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciint __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr); 2938c2ecf20Sopenharmony_ciint __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr); 2948c2ecf20Sopenharmony_civoid ipv6_ac_destroy_dev(struct inet6_dev *idev); 2958c2ecf20Sopenharmony_cibool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, 2968c2ecf20Sopenharmony_ci const struct in6_addr *addr); 2978c2ecf20Sopenharmony_cibool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, 2988c2ecf20Sopenharmony_ci const struct in6_addr *addr); 2998c2ecf20Sopenharmony_ciint ipv6_anycast_init(void); 3008c2ecf20Sopenharmony_civoid ipv6_anycast_cleanup(void); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* Device notifier */ 3038c2ecf20Sopenharmony_ciint register_inet6addr_notifier(struct notifier_block *nb); 3048c2ecf20Sopenharmony_ciint unregister_inet6addr_notifier(struct notifier_block *nb); 3058c2ecf20Sopenharmony_ciint inet6addr_notifier_call_chain(unsigned long val, void *v); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ciint register_inet6addr_validator_notifier(struct notifier_block *nb); 3088c2ecf20Sopenharmony_ciint unregister_inet6addr_validator_notifier(struct notifier_block *nb); 3098c2ecf20Sopenharmony_ciint inet6addr_validator_notifier_call_chain(unsigned long val, void *v); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_civoid inet6_netconf_notify_devconf(struct net *net, int event, int type, 3128c2ecf20Sopenharmony_ci int ifindex, struct ipv6_devconf *devconf); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/** 3158c2ecf20Sopenharmony_ci * __in6_dev_get - get inet6_dev pointer from netdevice 3168c2ecf20Sopenharmony_ci * @dev: network device 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * Caller must hold rcu_read_lock or RTNL, because this function 3198c2ecf20Sopenharmony_ci * does not take a reference on the inet6_dev. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_cistatic inline struct inet6_dev *__in6_dev_get(const struct net_device *dev) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci return rcu_dereference_rtnl(dev->ip6_ptr); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/** 3278c2ecf20Sopenharmony_ci * __in6_dev_stats_get - get inet6_dev pointer for stats 3288c2ecf20Sopenharmony_ci * @dev: network device 3298c2ecf20Sopenharmony_ci * @skb: skb for original incoming interface if neeeded 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * Caller must hold rcu_read_lock or RTNL, because this function 3328c2ecf20Sopenharmony_ci * does not take a reference on the inet6_dev. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_cistatic inline struct inet6_dev *__in6_dev_stats_get(const struct net_device *dev, 3358c2ecf20Sopenharmony_ci const struct sk_buff *skb) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci if (netif_is_l3_master(dev)) 3388c2ecf20Sopenharmony_ci dev = dev_get_by_index_rcu(dev_net(dev), inet6_iif(skb)); 3398c2ecf20Sopenharmony_ci return __in6_dev_get(dev); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/** 3438c2ecf20Sopenharmony_ci * __in6_dev_get_safely - get inet6_dev pointer from netdevice 3448c2ecf20Sopenharmony_ci * @dev: network device 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * This is a safer version of __in6_dev_get 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_cistatic inline struct inet6_dev *__in6_dev_get_safely(const struct net_device *dev) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci if (likely(dev)) 3518c2ecf20Sopenharmony_ci return rcu_dereference_rtnl(dev->ip6_ptr); 3528c2ecf20Sopenharmony_ci else 3538c2ecf20Sopenharmony_ci return NULL; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/** 3578c2ecf20Sopenharmony_ci * in6_dev_get - get inet6_dev pointer from netdevice 3588c2ecf20Sopenharmony_ci * @dev: network device 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * This version can be used in any context, and takes a reference 3618c2ecf20Sopenharmony_ci * on the inet6_dev. Callers must use in6_dev_put() later to 3628c2ecf20Sopenharmony_ci * release this reference. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic inline struct inet6_dev *in6_dev_get(const struct net_device *dev) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct inet6_dev *idev; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci rcu_read_lock(); 3698c2ecf20Sopenharmony_ci idev = rcu_dereference(dev->ip6_ptr); 3708c2ecf20Sopenharmony_ci if (idev) 3718c2ecf20Sopenharmony_ci refcount_inc(&idev->refcnt); 3728c2ecf20Sopenharmony_ci rcu_read_unlock(); 3738c2ecf20Sopenharmony_ci return idev; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic inline struct neigh_parms *__in6_dev_nd_parms_get_rcu(const struct net_device *dev) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct inet6_dev *idev = __in6_dev_get(dev); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return idev ? idev->nd_parms : NULL; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_civoid in6_dev_finish_destroy(struct inet6_dev *idev); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic inline void in6_dev_put(struct inet6_dev *idev) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&idev->refcnt)) 3888c2ecf20Sopenharmony_ci in6_dev_finish_destroy(idev); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic inline void in6_dev_put_clear(struct inet6_dev **pidev) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct inet6_dev *idev = *pidev; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (idev) { 3968c2ecf20Sopenharmony_ci in6_dev_put(idev); 3978c2ecf20Sopenharmony_ci *pidev = NULL; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic inline void __in6_dev_put(struct inet6_dev *idev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci refcount_dec(&idev->refcnt); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic inline void in6_dev_hold(struct inet6_dev *idev) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci refcount_inc(&idev->refcnt); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/* called with rcu_read_lock held */ 4128c2ecf20Sopenharmony_cistatic inline bool ip6_ignore_linkdown(const struct net_device *dev) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci const struct inet6_dev *idev = __in6_dev_get(dev); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (unlikely(!idev)) 4178c2ecf20Sopenharmony_ci return true; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return !!idev->cnf.ignore_routes_with_linkdown; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_civoid inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic inline void in6_ifa_put(struct inet6_ifaddr *ifp) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&ifp->refcnt)) 4278c2ecf20Sopenharmony_ci inet6_ifa_finish_destroy(ifp); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic inline void __in6_ifa_put(struct inet6_ifaddr *ifp) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci refcount_dec(&ifp->refcnt); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic inline void in6_ifa_hold(struct inet6_ifaddr *ifp) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci refcount_inc(&ifp->refcnt); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic inline bool in6_ifa_hold_safe(struct inet6_ifaddr *ifp) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci return refcount_inc_not_zero(&ifp->refcnt); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* 4468c2ecf20Sopenharmony_ci * compute link-local solicited-node multicast address 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic inline void addrconf_addr_solict_mult(const struct in6_addr *addr, 4508c2ecf20Sopenharmony_ci struct in6_addr *solicited) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci ipv6_addr_set(solicited, 4538c2ecf20Sopenharmony_ci htonl(0xFF020000), 0, 4548c2ecf20Sopenharmony_ci htonl(0x1), 4558c2ecf20Sopenharmony_ci htonl(0xFF000000) | addr->s6_addr32[3]); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 4618c2ecf20Sopenharmony_ci __be64 *p = (__force __be64 *)addr; 4628c2ecf20Sopenharmony_ci return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(1))) == 0UL; 4638c2ecf20Sopenharmony_ci#else 4648c2ecf20Sopenharmony_ci return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | 4658c2ecf20Sopenharmony_ci addr->s6_addr32[1] | addr->s6_addr32[2] | 4668c2ecf20Sopenharmony_ci (addr->s6_addr32[3] ^ htonl(0x00000001))) == 0; 4678c2ecf20Sopenharmony_ci#endif 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_ll_all_routers(const struct in6_addr *addr) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 4738c2ecf20Sopenharmony_ci __be64 *p = (__force __be64 *)addr; 4748c2ecf20Sopenharmony_ci return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(2))) == 0UL; 4758c2ecf20Sopenharmony_ci#else 4768c2ecf20Sopenharmony_ci return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | 4778c2ecf20Sopenharmony_ci addr->s6_addr32[1] | addr->s6_addr32[2] | 4788c2ecf20Sopenharmony_ci (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0; 4798c2ecf20Sopenharmony_ci#endif 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_isatap(const struct in6_addr *addr) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 4908c2ecf20Sopenharmony_ci __be64 *p = (__force __be64 *)addr; 4918c2ecf20Sopenharmony_ci return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | 4928c2ecf20Sopenharmony_ci ((p[1] ^ cpu_to_be64(0x00000001ff000000UL)) & 4938c2ecf20Sopenharmony_ci cpu_to_be64(0xffffffffff000000UL))) == 0UL; 4948c2ecf20Sopenharmony_ci#else 4958c2ecf20Sopenharmony_ci return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | 4968c2ecf20Sopenharmony_ci addr->s6_addr32[1] | 4978c2ecf20Sopenharmony_ci (addr->s6_addr32[2] ^ htonl(0x00000001)) | 4988c2ecf20Sopenharmony_ci (addr->s6_addr[12] ^ 0xff)) == 0; 4998c2ecf20Sopenharmony_ci#endif 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_all_snoopers(const struct in6_addr *addr) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 5058c2ecf20Sopenharmony_ci __be64 *p = (__force __be64 *)addr; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | 5088c2ecf20Sopenharmony_ci (p[1] ^ cpu_to_be64(0x6a))) == 0UL; 5098c2ecf20Sopenharmony_ci#else 5108c2ecf20Sopenharmony_ci return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | 5118c2ecf20Sopenharmony_ci addr->s6_addr32[1] | addr->s6_addr32[2] | 5128c2ecf20Sopenharmony_ci (addr->s6_addr32[3] ^ htonl(0x0000006a))) == 0; 5138c2ecf20Sopenharmony_ci#endif 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 5178c2ecf20Sopenharmony_ciint if6_proc_init(void); 5188c2ecf20Sopenharmony_civoid if6_proc_exit(void); 5198c2ecf20Sopenharmony_ci#endif 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci#endif 522