162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IPv6 library code, needed by static components when full IPv6 support is 462306a36Sopenharmony_ci * not configured or static. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/export.h> 862306a36Sopenharmony_ci#include <net/ipv6.h> 962306a36Sopenharmony_ci#include <net/ipv6_stubs.h> 1062306a36Sopenharmony_ci#include <net/addrconf.h> 1162306a36Sopenharmony_ci#include <net/ip.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* if ipv6 module registers this function is used by xfrm to force all 1462306a36Sopenharmony_ci * sockets to relookup their nodes - this is fairly expensive, be 1562306a36Sopenharmony_ci * careful 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_civoid (*__fib6_flush_trees)(struct net *); 1862306a36Sopenharmony_ciEXPORT_SYMBOL(__fib6_flush_trees); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic inline unsigned int ipv6_addr_scope2type(unsigned int scope) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci switch (scope) { 2562306a36Sopenharmony_ci case IPV6_ADDR_SCOPE_NODELOCAL: 2662306a36Sopenharmony_ci return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) | 2762306a36Sopenharmony_ci IPV6_ADDR_LOOPBACK); 2862306a36Sopenharmony_ci case IPV6_ADDR_SCOPE_LINKLOCAL: 2962306a36Sopenharmony_ci return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) | 3062306a36Sopenharmony_ci IPV6_ADDR_LINKLOCAL); 3162306a36Sopenharmony_ci case IPV6_ADDR_SCOPE_SITELOCAL: 3262306a36Sopenharmony_ci return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) | 3362306a36Sopenharmony_ci IPV6_ADDR_SITELOCAL); 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci return IPV6_ADDR_SCOPE_TYPE(scope); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint __ipv6_addr_type(const struct in6_addr *addr) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci __be32 st; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci st = addr->s6_addr32[0]; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* Consider all addresses with the first three bits different of 4562306a36Sopenharmony_ci 000 and 111 as unicasts. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci if ((st & htonl(0xE0000000)) != htonl(0x00000000) && 4862306a36Sopenharmony_ci (st & htonl(0xE0000000)) != htonl(0xE0000000)) 4962306a36Sopenharmony_ci return (IPV6_ADDR_UNICAST | 5062306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { 5362306a36Sopenharmony_ci /* multicast */ 5462306a36Sopenharmony_ci /* addr-select 3.1 */ 5562306a36Sopenharmony_ci return (IPV6_ADDR_MULTICAST | 5662306a36Sopenharmony_ci ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr))); 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) 6062306a36Sopenharmony_ci return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | 6162306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */ 6262306a36Sopenharmony_ci if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) 6362306a36Sopenharmony_ci return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST | 6462306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */ 6562306a36Sopenharmony_ci if ((st & htonl(0xFE000000)) == htonl(0xFC000000)) 6662306a36Sopenharmony_ci return (IPV6_ADDR_UNICAST | 6762306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* RFC 4193 */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { 7062306a36Sopenharmony_ci if (addr->s6_addr32[2] == 0) { 7162306a36Sopenharmony_ci if (addr->s6_addr32[3] == 0) 7262306a36Sopenharmony_ci return IPV6_ADDR_ANY; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (addr->s6_addr32[3] == htonl(0x00000001)) 7562306a36Sopenharmony_ci return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST | 7662306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST | 7962306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (addr->s6_addr32[2] == htonl(0x0000ffff)) 8362306a36Sopenharmony_ci return (IPV6_ADDR_MAPPED | 8462306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return (IPV6_ADDR_UNICAST | 8862306a36Sopenharmony_ci IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ciEXPORT_SYMBOL(__ipv6_addr_type); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic ATOMIC_NOTIFIER_HEAD(inet6addr_chain); 9362306a36Sopenharmony_cistatic BLOCKING_NOTIFIER_HEAD(inet6addr_validator_chain); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciint register_inet6addr_notifier(struct notifier_block *nb) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci return atomic_notifier_chain_register(&inet6addr_chain, nb); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ciEXPORT_SYMBOL(register_inet6addr_notifier); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint unregister_inet6addr_notifier(struct notifier_block *nb) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return atomic_notifier_chain_unregister(&inet6addr_chain, nb); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_inet6addr_notifier); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciint inet6addr_notifier_call_chain(unsigned long val, void *v) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return atomic_notifier_call_chain(&inet6addr_chain, val, v); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL(inet6addr_notifier_call_chain); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciint register_inet6addr_validator_notifier(struct notifier_block *nb) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return blocking_notifier_chain_register(&inet6addr_validator_chain, nb); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ciEXPORT_SYMBOL(register_inet6addr_validator_notifier); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciint unregister_inet6addr_validator_notifier(struct notifier_block *nb) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci return blocking_notifier_chain_unregister(&inet6addr_validator_chain, 12262306a36Sopenharmony_ci nb); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_inet6addr_validator_notifier); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciint inet6addr_validator_notifier_call_chain(unsigned long val, void *v) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci return blocking_notifier_call_chain(&inet6addr_validator_chain, val, v); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ciEXPORT_SYMBOL(inet6addr_validator_notifier_call_chain); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic struct dst_entry *eafnosupport_ipv6_dst_lookup_flow(struct net *net, 13362306a36Sopenharmony_ci const struct sock *sk, 13462306a36Sopenharmony_ci struct flowi6 *fl6, 13562306a36Sopenharmony_ci const struct in6_addr *final_dst) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return ERR_PTR(-EAFNOSUPPORT); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int eafnosupport_ipv6_route_input(struct sk_buff *skb) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return -EAFNOSUPPORT; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic struct fib6_table *eafnosupport_fib6_get_table(struct net *net, u32 id) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci return NULL; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int 15162306a36Sopenharmony_cieafnosupport_fib6_table_lookup(struct net *net, struct fib6_table *table, 15262306a36Sopenharmony_ci int oif, struct flowi6 *fl6, 15362306a36Sopenharmony_ci struct fib6_result *res, int flags) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return -EAFNOSUPPORT; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int 15962306a36Sopenharmony_cieafnosupport_fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, 16062306a36Sopenharmony_ci struct fib6_result *res, int flags) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci return -EAFNOSUPPORT; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void 16662306a36Sopenharmony_cieafnosupport_fib6_select_path(const struct net *net, struct fib6_result *res, 16762306a36Sopenharmony_ci struct flowi6 *fl6, int oif, bool have_oif_match, 16862306a36Sopenharmony_ci const struct sk_buff *skb, int strict) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic u32 17362306a36Sopenharmony_cieafnosupport_ip6_mtu_from_fib6(const struct fib6_result *res, 17462306a36Sopenharmony_ci const struct in6_addr *daddr, 17562306a36Sopenharmony_ci const struct in6_addr *saddr) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int eafnosupport_fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, 18162306a36Sopenharmony_ci struct fib6_config *cfg, gfp_t gfp_flags, 18262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "IPv6 support not enabled in kernel"); 18562306a36Sopenharmony_ci return -EAFNOSUPPORT; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int eafnosupport_ip6_del_rt(struct net *net, struct fib6_info *rt, 18962306a36Sopenharmony_ci bool skip_notify) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci return -EAFNOSUPPORT; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int eafnosupport_ipv6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, 19562306a36Sopenharmony_ci int (*output)(struct net *, struct sock *, struct sk_buff *)) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci kfree_skb(skb); 19862306a36Sopenharmony_ci return -EAFNOSUPPORT; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic struct net_device *eafnosupport_ipv6_dev_find(struct net *net, const struct in6_addr *addr, 20262306a36Sopenharmony_ci struct net_device *dev) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci return ERR_PTR(-EAFNOSUPPORT); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciconst struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { 20862306a36Sopenharmony_ci .ipv6_dst_lookup_flow = eafnosupport_ipv6_dst_lookup_flow, 20962306a36Sopenharmony_ci .ipv6_route_input = eafnosupport_ipv6_route_input, 21062306a36Sopenharmony_ci .fib6_get_table = eafnosupport_fib6_get_table, 21162306a36Sopenharmony_ci .fib6_table_lookup = eafnosupport_fib6_table_lookup, 21262306a36Sopenharmony_ci .fib6_lookup = eafnosupport_fib6_lookup, 21362306a36Sopenharmony_ci .fib6_select_path = eafnosupport_fib6_select_path, 21462306a36Sopenharmony_ci .ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6, 21562306a36Sopenharmony_ci .fib6_nh_init = eafnosupport_fib6_nh_init, 21662306a36Sopenharmony_ci .ip6_del_rt = eafnosupport_ip6_del_rt, 21762306a36Sopenharmony_ci .ipv6_fragment = eafnosupport_ipv6_fragment, 21862306a36Sopenharmony_ci .ipv6_dev_find = eafnosupport_ipv6_dev_find, 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipv6_stub); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ 22362306a36Sopenharmony_ciconst struct in6_addr in6addr_loopback __aligned(BITS_PER_LONG/8) 22462306a36Sopenharmony_ci = IN6ADDR_LOOPBACK_INIT; 22562306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_loopback); 22662306a36Sopenharmony_ciconst struct in6_addr in6addr_any __aligned(BITS_PER_LONG/8) 22762306a36Sopenharmony_ci = IN6ADDR_ANY_INIT; 22862306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_any); 22962306a36Sopenharmony_ciconst struct in6_addr in6addr_linklocal_allnodes __aligned(BITS_PER_LONG/8) 23062306a36Sopenharmony_ci = IN6ADDR_LINKLOCAL_ALLNODES_INIT; 23162306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_linklocal_allnodes); 23262306a36Sopenharmony_ciconst struct in6_addr in6addr_linklocal_allrouters __aligned(BITS_PER_LONG/8) 23362306a36Sopenharmony_ci = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; 23462306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_linklocal_allrouters); 23562306a36Sopenharmony_ciconst struct in6_addr in6addr_interfacelocal_allnodes __aligned(BITS_PER_LONG/8) 23662306a36Sopenharmony_ci = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT; 23762306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_interfacelocal_allnodes); 23862306a36Sopenharmony_ciconst struct in6_addr in6addr_interfacelocal_allrouters __aligned(BITS_PER_LONG/8) 23962306a36Sopenharmony_ci = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT; 24062306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_interfacelocal_allrouters); 24162306a36Sopenharmony_ciconst struct in6_addr in6addr_sitelocal_allrouters __aligned(BITS_PER_LONG/8) 24262306a36Sopenharmony_ci = IN6ADDR_SITELOCAL_ALLROUTERS_INIT; 24362306a36Sopenharmony_ciEXPORT_SYMBOL(in6addr_sitelocal_allrouters); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic void snmp6_free_dev(struct inet6_dev *idev) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci kfree(idev->stats.icmpv6msgdev); 24862306a36Sopenharmony_ci kfree(idev->stats.icmpv6dev); 24962306a36Sopenharmony_ci free_percpu(idev->stats.ipv6); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void in6_dev_finish_destroy_rcu(struct rcu_head *head) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci snmp6_free_dev(idev); 25762306a36Sopenharmony_ci kfree(idev); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* Nobody refers to this device, we may destroy it. */ 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_civoid in6_dev_finish_destroy(struct inet6_dev *idev) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct net_device *dev = idev->dev; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci WARN_ON(!list_empty(&idev->addr_list)); 26762306a36Sopenharmony_ci WARN_ON(rcu_access_pointer(idev->mc_list)); 26862306a36Sopenharmony_ci WARN_ON(timer_pending(&idev->rs_timer)); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci#ifdef NET_REFCNT_DEBUG 27162306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL"); 27262306a36Sopenharmony_ci#endif 27362306a36Sopenharmony_ci netdev_put(dev, &idev->dev_tracker); 27462306a36Sopenharmony_ci if (!idev->dead) { 27562306a36Sopenharmony_ci pr_warn("Freeing alive inet6 device %p\n", idev); 27662306a36Sopenharmony_ci return; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ciEXPORT_SYMBOL(in6_dev_finish_destroy); 281