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>
2013-06-25 12:30:11 +04: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
# 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 ) ;
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
const struct ipv6_stub * ipv6_stub __read_mostly ;
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 ) ;
snmp_mib_free ( ( void __percpu * * ) idev - > stats . ipv6 ) ;
}
/* 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 ) ) ;
WARN_ON ( idev - > mc_list ! = NULL ) ;
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 ;
}
snmp6_free_dev ( idev ) ;
kfree_rcu ( idev , rcu ) ;
}
EXPORT_SYMBOL ( in6_dev_finish_destroy ) ;