2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2007-02-21 20:25:42 +03:00
/*
* IPv6 library code , needed by static components when full IPv6 support is
* not configured or static .
*/
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2007-02-21 20:25:42 +03:00
# include <net/ipv6.h>
2019-03-22 16:06:09 +03:00
# include <net/ipv6_stubs.h>
2019-10-22 17:44:40 +03:00
# include <net/addrconf.h>
2013-08-31 09:44:35 +04:00
# include <net/ip.h>
2007-02-21 20:25:42 +03:00
2014-09-28 02:46:06 +04:00
/* if ipv6 module registers this function is used by xfrm to force all
* sockets to relookup their nodes - this is fairly expensive , be
* careful
*/
void ( * __fib6_flush_trees ) ( struct net * ) ;
EXPORT_SYMBOL ( __fib6_flush_trees ) ;
2007-02-21 20:25:42 +03:00
# define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
2012-04-15 09:58:06 +04:00
static inline unsigned int ipv6_addr_scope2type ( unsigned int scope )
2007-02-21 20:25:42 +03:00
{
2012-04-01 11:49:02 +04:00
switch ( scope ) {
2007-02-21 20:25:42 +03:00
case IPV6_ADDR_SCOPE_NODELOCAL :
return ( IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_NODELOCAL ) |
IPV6_ADDR_LOOPBACK ) ;
case IPV6_ADDR_SCOPE_LINKLOCAL :
return ( IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_LINKLOCAL ) |
IPV6_ADDR_LINKLOCAL ) ;
case IPV6_ADDR_SCOPE_SITELOCAL :
return ( IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_SITELOCAL ) |
IPV6_ADDR_SITELOCAL ) ;
}
return IPV6_ADDR_SCOPE_TYPE ( scope ) ;
}
int __ipv6_addr_type ( const struct in6_addr * addr )
{
__be32 st ;
st = addr - > s6_addr32 [ 0 ] ;
/* Consider all addresses with the first three bits different of
000 and 111 as unicasts .
*/
if ( ( st & htonl ( 0xE0000000 ) ) ! = htonl ( 0x00000000 ) & &
( st & htonl ( 0xE0000000 ) ) ! = htonl ( 0xE0000000 ) )
return ( IPV6_ADDR_UNICAST |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_GLOBAL ) ) ;
if ( ( st & htonl ( 0xFF000000 ) ) = = htonl ( 0xFF000000 ) ) {
/* multicast */
/* addr-select 3.1 */
return ( IPV6_ADDR_MULTICAST |
ipv6_addr_scope2type ( IPV6_ADDR_MC_SCOPE ( addr ) ) ) ;
}
if ( ( st & htonl ( 0xFFC00000 ) ) = = htonl ( 0xFE800000 ) )
return ( IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_LINKLOCAL ) ) ; /* addr-select 3.1 */
if ( ( st & htonl ( 0xFFC00000 ) ) = = htonl ( 0xFEC00000 ) )
return ( IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_SITELOCAL ) ) ; /* addr-select 3.1 */
2007-07-31 04:19:31 +04:00
if ( ( st & htonl ( 0xFE000000 ) ) = = htonl ( 0xFC000000 ) )
return ( IPV6_ADDR_UNICAST |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_GLOBAL ) ) ; /* RFC 4193 */
2007-02-21 20:25:42 +03:00
if ( ( addr - > s6_addr32 [ 0 ] | addr - > s6_addr32 [ 1 ] ) = = 0 ) {
if ( addr - > s6_addr32 [ 2 ] = = 0 ) {
if ( addr - > s6_addr32 [ 3 ] = = 0 )
return IPV6_ADDR_ANY ;
if ( addr - > s6_addr32 [ 3 ] = = htonl ( 0x00000001 ) )
return ( IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_LINKLOCAL ) ) ; /* addr-select 3.4 */
return ( IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_GLOBAL ) ) ; /* addr-select 3.3 */
}
if ( addr - > s6_addr32 [ 2 ] = = htonl ( 0x0000ffff ) )
return ( IPV6_ADDR_MAPPED |
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_GLOBAL ) ) ; /* addr-select 3.3 */
}
2010-02-26 02:28:58 +03:00
return ( IPV6_ADDR_UNICAST |
2007-02-21 20:25:42 +03:00
IPV6_ADDR_SCOPE_TYPE ( IPV6_ADDR_SCOPE_GLOBAL ) ) ; /* addr-select 3.4 */
}
2007-02-22 10:26:56 +03:00
EXPORT_SYMBOL ( __ipv6_addr_type ) ;
2007-02-21 20:25:42 +03:00
2013-04-14 19:18:43 +04:00
static ATOMIC_NOTIFIER_HEAD ( inet6addr_chain ) ;
2017-10-18 19:56:53 +03:00
static BLOCKING_NOTIFIER_HEAD ( inet6addr_validator_chain ) ;
2013-04-14 19:18:43 +04:00
int register_inet6addr_notifier ( struct notifier_block * nb )
{
return atomic_notifier_chain_register ( & inet6addr_chain , nb ) ;
}
EXPORT_SYMBOL ( register_inet6addr_notifier ) ;
int unregister_inet6addr_notifier ( struct notifier_block * nb )
{
return atomic_notifier_chain_unregister ( & inet6addr_chain , nb ) ;
}
EXPORT_SYMBOL ( unregister_inet6addr_notifier ) ;
int inet6addr_notifier_call_chain ( unsigned long val , void * v )
{
return atomic_notifier_call_chain ( & inet6addr_chain , val , v ) ;
}
EXPORT_SYMBOL ( inet6addr_notifier_call_chain ) ;
2013-08-31 09:44:30 +04:00
2017-06-08 23:12:14 +03:00
int register_inet6addr_validator_notifier ( struct notifier_block * nb )
{
2017-10-18 19:56:53 +03:00
return blocking_notifier_chain_register ( & inet6addr_validator_chain , nb ) ;
2017-06-08 23:12:14 +03:00
}
EXPORT_SYMBOL ( register_inet6addr_validator_notifier ) ;
int unregister_inet6addr_validator_notifier ( struct notifier_block * nb )
{
2017-10-18 19:56:53 +03:00
return blocking_notifier_chain_unregister ( & inet6addr_validator_chain ,
nb ) ;
2017-06-08 23:12:14 +03:00
}
EXPORT_SYMBOL ( unregister_inet6addr_validator_notifier ) ;
int inet6addr_validator_notifier_call_chain ( unsigned long val , void * v )
{
2017-10-18 19:56:53 +03:00
return blocking_notifier_call_chain ( & inet6addr_validator_chain , val , v ) ;
2017-06-08 23:12:14 +03:00
}
EXPORT_SYMBOL ( inet6addr_validator_notifier_call_chain ) ;
2019-12-04 17:35:53 +03:00
static struct dst_entry * eafnosupport_ipv6_dst_lookup_flow ( struct net * net ,
const struct sock * sk ,
struct flowi6 * fl6 ,
const struct in6_addr * final_dst )
2015-07-30 23:34:53 +03:00
{
2019-12-04 17:35:53 +03:00
return ERR_PTR ( - EAFNOSUPPORT ) ;
2015-07-30 23:34:53 +03:00
}
2019-02-13 22:53:38 +03:00
static int eafnosupport_ipv6_route_input ( struct sk_buff * skb )
{
return - EAFNOSUPPORT ;
}
2018-05-10 06:34:25 +03:00
static struct fib6_table * eafnosupport_fib6_get_table ( struct net * net , u32 id )
{
return NULL ;
}
2019-04-17 00:36:10 +03:00
static int
2018-05-10 06:34:25 +03:00
eafnosupport_fib6_table_lookup ( struct net * net , struct fib6_table * table ,
2019-04-17 00:36:10 +03:00
int oif , struct flowi6 * fl6 ,
struct fib6_result * res , int flags )
2018-05-10 06:34:25 +03:00
{
2019-04-17 00:36:10 +03:00
return - EAFNOSUPPORT ;
2018-05-10 06:34:25 +03:00
}
2019-04-17 00:36:10 +03:00
static int
2018-05-10 06:34:25 +03:00
eafnosupport_fib6_lookup ( struct net * net , int oif , struct flowi6 * fl6 ,
2019-04-17 00:36:10 +03:00
struct fib6_result * res , int flags )
2018-05-10 06:34:25 +03:00
{
2019-04-17 00:36:10 +03:00
return - EAFNOSUPPORT ;
2018-05-10 06:34:25 +03:00
}
2019-04-17 00:35:59 +03:00
static void
eafnosupport_fib6_select_path ( const struct net * net , struct fib6_result * res ,
struct flowi6 * fl6 , int oif , bool have_oif_match ,
const struct sk_buff * skb , int strict )
2018-05-10 06:34:25 +03:00
{
}
2018-05-21 19:08:14 +03:00
static u32
2019-04-17 00:36:06 +03:00
eafnosupport_ip6_mtu_from_fib6 ( const struct fib6_result * res ,
const struct in6_addr * daddr ,
const struct in6_addr * saddr )
2018-05-21 19:08:14 +03:00
{
return 0 ;
}
2019-04-06 02:30:24 +03:00
static int eafnosupport_fib6_nh_init ( struct net * net , struct fib6_nh * fib6_nh ,
struct fib6_config * cfg , gfp_t gfp_flags ,
struct netlink_ext_ack * extack )
{
NL_SET_ERR_MSG ( extack , " IPv6 support not enabled in kernel " ) ;
return - EAFNOSUPPORT ;
}
2020-04-27 23:56:45 +03:00
static int eafnosupport_ip6_del_rt ( struct net * net , struct fib6_info * rt ,
bool skip_notify )
2019-05-22 22:04:39 +03:00
{
return - EAFNOSUPPORT ;
}
2015-07-30 23:34:53 +03:00
const struct ipv6_stub * ipv6_stub __read_mostly = & ( struct ipv6_stub ) {
2019-12-04 17:35:53 +03:00
. ipv6_dst_lookup_flow = eafnosupport_ipv6_dst_lookup_flow ,
2019-02-13 22:53:38 +03:00
. ipv6_route_input = eafnosupport_ipv6_route_input ,
2018-05-10 06:34:25 +03:00
. fib6_get_table = eafnosupport_fib6_get_table ,
. fib6_table_lookup = eafnosupport_fib6_table_lookup ,
. fib6_lookup = eafnosupport_fib6_lookup ,
2019-04-17 00:35:59 +03:00
. fib6_select_path = eafnosupport_fib6_select_path ,
2018-05-21 19:08:14 +03:00
. ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6 ,
2019-04-06 02:30:24 +03:00
. fib6_nh_init = eafnosupport_fib6_nh_init ,
2019-05-22 22:04:39 +03:00
. ip6_del_rt = eafnosupport_ip6_del_rt ,
2015-07-30 23:34:53 +03:00
} ;
2013-08-31 09:44:30 +04:00
EXPORT_SYMBOL_GPL ( ipv6_stub ) ;
2013-08-31 09:44:31 +04:00
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT ;
EXPORT_SYMBOL ( in6addr_loopback ) ;
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT ;
EXPORT_SYMBOL ( in6addr_any ) ;
const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT ;
EXPORT_SYMBOL ( in6addr_linklocal_allnodes ) ;
const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT ;
EXPORT_SYMBOL ( in6addr_linklocal_allrouters ) ;
const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT ;
EXPORT_SYMBOL ( in6addr_interfacelocal_allnodes ) ;
const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT ;
EXPORT_SYMBOL ( in6addr_interfacelocal_allrouters ) ;
const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT ;
EXPORT_SYMBOL ( in6addr_sitelocal_allrouters ) ;
2013-08-31 09:44:35 +04:00
static void snmp6_free_dev ( struct inet6_dev * idev )
{
kfree ( idev - > stats . icmpv6msgdev ) ;
kfree ( idev - > stats . icmpv6dev ) ;
2014-05-06 02:55:55 +04:00
free_percpu ( idev - > stats . ipv6 ) ;
2013-08-31 09:44:35 +04:00
}
2015-06-05 20:51:54 +03:00
static void in6_dev_finish_destroy_rcu ( struct rcu_head * head )
{
struct inet6_dev * idev = container_of ( head , struct inet6_dev , rcu ) ;
snmp6_free_dev ( idev ) ;
kfree ( idev ) ;
}
2013-08-31 09:44:35 +04:00
/* Nobody refers to this device, we may destroy it. */
void in6_dev_finish_destroy ( struct inet6_dev * idev )
{
struct net_device * dev = idev - > dev ;
WARN_ON ( ! list_empty ( & idev - > addr_list ) ) ;
2015-03-29 16:00:05 +03:00
WARN_ON ( idev - > mc_list ) ;
2013-08-31 09:44:35 +04:00
WARN_ON ( timer_pending ( & idev - > rs_timer ) ) ;
# ifdef NET_REFCNT_DEBUG
pr_debug ( " %s: %s \n " , __func__ , dev ? dev - > name : " NIL " ) ;
# endif
dev_put ( dev ) ;
if ( ! idev - > dead ) {
pr_warn ( " Freeing alive inet6 device %p \n " , idev ) ;
return ;
}
2015-06-05 20:51:54 +03:00
call_rcu ( & idev - > rcu , in6_dev_finish_destroy_rcu ) ;
2013-08-31 09:44:35 +04:00
}
EXPORT_SYMBOL ( in6_dev_finish_destroy ) ;