2005-04-17 02:20:36 +04:00
/*
* Linux INET6 implementation
*
* Authors :
* Pedro Roque < roque @ di . fc . ul . pt >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# ifndef _NET_IPV6_H
# define _NET_IPV6_H
# include <linux/ipv6.h>
# include <linux/hardirq.h>
2007-07-31 04:05:49 +04:00
# include <net/if_inet6.h>
2005-04-17 02:20:36 +04:00
# include <net/ndisc.h>
# include <net/flow.h>
# include <net/snmp.h>
# define SIN6_LEN_RFC2133 24
# define IPV6_MAXPLEN 65535
/*
* NextHeader field of IPv6 header
*/
# define NEXTHDR_HOP 0 /* Hop-by-hop option header. */
# define NEXTHDR_TCP 6 /* TCP segment. */
# define NEXTHDR_UDP 17 /* UDP message. */
# define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */
# define NEXTHDR_ROUTING 43 /* Routing header. */
# define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
2012-08-10 04:51:50 +04:00
# define NEXTHDR_GRE 47 /* GRE header. */
2005-04-17 02:20:36 +04:00
# define NEXTHDR_ESP 50 /* Encapsulating security payload. */
# define NEXTHDR_AUTH 51 /* Authentication header. */
# define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
# define NEXTHDR_NONE 59 /* No next header */
# define NEXTHDR_DEST 60 /* Destination options header. */
2006-08-24 07:34:26 +04:00
# define NEXTHDR_MOBILITY 135 /* Mobility header. */
2005-04-17 02:20:36 +04:00
# define NEXTHDR_MAX 255
# define IPV6_DEFAULT_HOPLIMIT 64
# define IPV6_DEFAULT_MCASTHOPS 1
/*
* Addr type
*
* type - unicast | multicast
* scope - local | site | global
* v4 - compat
* v4mapped
* any
* loopback
*/
# define IPV6_ADDR_ANY 0x0000U
# define IPV6_ADDR_UNICAST 0x0001U
# define IPV6_ADDR_MULTICAST 0x0002U
# define IPV6_ADDR_LOOPBACK 0x0010U
# define IPV6_ADDR_LINKLOCAL 0x0020U
# define IPV6_ADDR_SITELOCAL 0x0040U
# define IPV6_ADDR_COMPATv4 0x0080U
# define IPV6_ADDR_SCOPE_MASK 0x00f0U
# define IPV6_ADDR_MAPPED 0x1000U
/*
* Addr scopes
*/
# define IPV6_ADDR_MC_SCOPE(a) \
( ( a ) - > s6_addr [ 1 ] & 0x0f ) /* nonstandard */
# define __IPV6_ADDR_SCOPE_INVALID -1
# define IPV6_ADDR_SCOPE_NODELOCAL 0x01
# define IPV6_ADDR_SCOPE_LINKLOCAL 0x02
# define IPV6_ADDR_SCOPE_SITELOCAL 0x05
# define IPV6_ADDR_SCOPE_ORGLOCAL 0x08
# define IPV6_ADDR_SCOPE_GLOBAL 0x0e
2011-02-15 16:19:20 +03:00
/*
* Addr flags
*/
# define IPV6_ADDR_MC_FLAG_TRANSIENT(a) \
( ( a ) - > s6_addr [ 1 ] & 0x10 )
# define IPV6_ADDR_MC_FLAG_PREFIX(a) \
( ( a ) - > s6_addr [ 1 ] & 0x20 )
# define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a) \
( ( a ) - > s6_addr [ 1 ] & 0x40 )
2005-04-17 02:20:36 +04:00
/*
* fragmentation header
*/
struct frag_hdr {
2006-11-08 11:21:46 +03:00
__u8 nexthdr ;
__u8 reserved ;
__be16 frag_off ;
__be32 identification ;
2005-04-17 02:20:36 +04:00
} ;
# define IP6_MF 0x0001
# include <net/sock.h>
/* sysctls */
extern int sysctl_mld_max_msf ;
2008-01-09 11:33:11 +03:00
2008-10-08 21:35:11 +04:00
# define _DEVINC(net, statname, modifier, idev, field) \
2007-09-17 03:52:35 +04:00
( { \
2006-11-04 14:11:37 +03:00
struct inet6_dev * _idev = ( idev ) ; \
if ( likely ( _idev ! = NULL ) ) \
2007-09-17 03:52:35 +04:00
SNMP_INC_STATS # # modifier ( ( _idev ) - > stats . statname , ( field ) ) ; \
2008-10-08 21:36:03 +04:00
SNMP_INC_STATS # # modifier ( ( net ) - > mib . statname # # _statistics , ( field ) ) ; \
2006-11-04 14:11:37 +03:00
} )
2007-09-17 03:52:35 +04:00
2011-05-19 05:14:23 +04:00
/* per device counters are atomic_long_t */
# define _DEVINCATOMIC(net, statname, modifier, idev, field) \
( { \
struct inet6_dev * _idev = ( idev ) ; \
if ( likely ( _idev ! = NULL ) ) \
SNMP_INC_STATS_ATOMIC_LONG ( ( _idev ) - > stats . statname # # dev , ( field ) ) ; \
SNMP_INC_STATS # # modifier ( ( net ) - > mib . statname # # _statistics , ( field ) ) ; \
} )
2011-11-13 05:24:04 +04:00
/* per device and per net counters are atomic_long_t */
# define _DEVINC_ATOMIC_ATOMIC(net, statname, idev, field) \
( { \
struct inet6_dev * _idev = ( idev ) ; \
if ( likely ( _idev ! = NULL ) ) \
SNMP_INC_STATS_ATOMIC_LONG ( ( _idev ) - > stats . statname # # dev , ( field ) ) ; \
SNMP_INC_STATS_ATOMIC_LONG ( ( net ) - > mib . statname # # _statistics , ( field ) ) ; \
} )
2008-10-08 21:35:11 +04:00
# define _DEVADD(net, statname, modifier, idev, field, val) \
2007-10-15 13:40:06 +04:00
( { \
struct inet6_dev * _idev = ( idev ) ; \
if ( likely ( _idev ! = NULL ) ) \
SNMP_ADD_STATS # # modifier ( ( _idev ) - > stats . statname , ( field ) , ( val ) ) ; \
2008-10-08 21:36:03 +04:00
SNMP_ADD_STATS # # modifier ( ( net ) - > mib . statname # # _statistics , ( field ) , ( val ) ) ; \
2007-10-15 13:40:06 +04:00
} )
2009-04-27 13:45:02 +04:00
# define _DEVUPD(net, statname, modifier, idev, field, val) \
( { \
struct inet6_dev * _idev = ( idev ) ; \
if ( likely ( _idev ! = NULL ) ) \
SNMP_UPD_PO_STATS # # modifier ( ( _idev ) - > stats . statname , field , ( val ) ) ; \
SNMP_UPD_PO_STATS # # modifier ( ( net ) - > mib . statname # # _statistics , field , ( val ) ) ; \
} )
2007-09-17 03:52:35 +04:00
/* MIBs */
2008-10-08 21:35:11 +04:00
# define IP6_INC_STATS(net, idev,field) \
2010-07-01 00:31:19 +04:00
_DEVINC ( net , ipv6 , 64 , idev , field )
2008-10-08 21:35:11 +04:00
# define IP6_INC_STATS_BH(net, idev,field) \
2010-07-01 00:31:19 +04:00
_DEVINC ( net , ipv6 , 64 _BH , idev , field )
2009-04-27 13:45:02 +04:00
# define IP6_ADD_STATS(net, idev,field,val) \
2010-07-01 00:31:19 +04:00
_DEVADD ( net , ipv6 , 64 , idev , field , val )
2008-10-08 21:35:11 +04:00
# define IP6_ADD_STATS_BH(net, idev,field,val) \
2010-07-01 00:31:19 +04:00
_DEVADD ( net , ipv6 , 64 _BH , idev , field , val )
2009-04-27 13:45:02 +04:00
# define IP6_UPD_PO_STATS(net, idev,field,val) \
2010-07-01 00:31:19 +04:00
_DEVUPD ( net , ipv6 , 64 , idev , field , val )
2009-04-27 13:45:02 +04:00
# define IP6_UPD_PO_STATS_BH(net, idev,field,val) \
2010-07-01 00:31:19 +04:00
_DEVUPD ( net , ipv6 , 64 _BH , idev , field , val )
2008-10-08 21:35:11 +04:00
# define ICMP6_INC_STATS(net, idev, field) \
2011-05-19 05:14:23 +04:00
_DEVINCATOMIC ( net , icmpv6 , , idev , field )
2008-10-08 21:35:11 +04:00
# define ICMP6_INC_STATS_BH(net, idev, field) \
2011-05-19 05:14:23 +04:00
_DEVINCATOMIC ( net , icmpv6 , _BH , idev , field )
2008-10-08 21:35:11 +04:00
# define ICMP6MSGOUT_INC_STATS(net, idev, field) \
2011-11-13 05:24:04 +04:00
_DEVINC_ATOMIC_ATOMIC ( net , icmpv6msg , idev , field + 256 )
2008-10-08 21:35:11 +04:00
# define ICMP6MSGOUT_INC_STATS_BH(net, idev, field) \
2011-11-13 05:24:04 +04:00
_DEVINC_ATOMIC_ATOMIC ( net , icmpv6msg , idev , field + 256 )
2008-10-08 21:35:11 +04:00
# define ICMP6MSGIN_INC_STATS_BH(net, idev, field) \
2011-11-13 05:24:04 +04:00
_DEVINC_ATOMIC_ATOMIC ( net , icmpv6msg , idev , field )
2007-09-17 03:52:35 +04:00
2009-11-03 06:26:03 +03:00
struct ip6_ra_chain {
2005-04-17 02:20:36 +04:00
struct ip6_ra_chain * next ;
struct sock * sk ;
int sel ;
void ( * destructor ) ( struct sock * ) ;
} ;
extern struct ip6_ra_chain * ip6_ra_chain ;
extern rwlock_t ip6_ra_lock ;
/*
This structure is prepared by protocol , when parsing
ancillary data and passed to IPv6 .
*/
2009-11-03 06:26:03 +03:00
struct ipv6_txoptions {
2005-04-17 02:20:36 +04:00
/* Length of this structure */
int tot_len ;
/* length of extension headers */
__u16 opt_flen ; /* after fragment hdr */
__u16 opt_nflen ; /* before fragment hdr */
struct ipv6_opt_hdr * hopopt ;
struct ipv6_opt_hdr * dst0opt ;
struct ipv6_rt_hdr * srcrt ; /* Routing Header */
struct ipv6_opt_hdr * dst1opt ;
/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
} ;
2009-11-03 06:26:03 +03:00
struct ip6_flowlabel {
2005-04-17 02:20:36 +04:00
struct ip6_flowlabel * next ;
2006-11-08 11:25:17 +03:00
__be32 label ;
2007-05-04 04:39:04 +04:00
atomic_t users ;
2005-04-17 02:20:36 +04:00
struct in6_addr dst ;
struct ipv6_txoptions * opt ;
unsigned long linger ;
u8 share ;
2012-05-24 20:37:59 +04:00
union {
struct pid * pid ;
kuid_t uid ;
} owner ;
2005-04-17 02:20:36 +04:00
unsigned long lastuse ;
unsigned long expires ;
2008-03-27 02:53:08 +03:00
struct net * fl_net ;
2005-04-17 02:20:36 +04:00
} ;
2009-02-15 09:58:35 +03:00
# define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF)
# define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF)
2005-04-17 02:20:36 +04:00
2009-11-03 06:26:03 +03:00
struct ipv6_fl_socklist {
2005-04-17 02:20:36 +04:00
struct ipv6_fl_socklist * next ;
struct ip6_flowlabel * fl ;
} ;
2006-11-08 11:25:17 +03:00
extern struct ip6_flowlabel * fl6_sock_lookup ( struct sock * sk , __be32 label ) ;
2005-04-17 02:20:36 +04:00
extern struct ipv6_txoptions * fl6_merge_options ( struct ipv6_txoptions * opt_space ,
struct ip6_flowlabel * fl ,
struct ipv6_txoptions * fopt ) ;
extern void fl6_free_socklist ( struct sock * sk ) ;
extern int ipv6_flowlabel_opt ( struct sock * sk , char __user * optval , int optlen ) ;
2007-12-11 13:23:18 +03:00
extern int ip6_flowlabel_init ( void ) ;
2005-04-17 02:20:36 +04:00
extern void ip6_flowlabel_cleanup ( void ) ;
static inline void fl6_sock_release ( struct ip6_flowlabel * fl )
{
if ( fl )
atomic_dec ( & fl - > users ) ;
}
2012-07-12 11:33:37 +04:00
extern void icmpv6_notify ( struct sk_buff * skb , u8 type , u8 code , __be32 info ) ;
2008-07-19 11:28:58 +04:00
extern int ip6_ra_control ( struct sock * sk , int sel ) ;
2005-04-17 02:20:36 +04:00
2007-10-15 23:50:28 +04:00
extern int ipv6_parse_hopopts ( struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
extern struct ipv6_txoptions * ipv6_dup_options ( struct sock * sk , struct ipv6_txoptions * opt ) ;
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 04:59:17 +04:00
extern struct ipv6_txoptions * ipv6_renew_options ( struct sock * sk , struct ipv6_txoptions * opt ,
int newtype ,
struct ipv6_opt_hdr __user * newopt ,
int newoptlen ) ;
2005-11-20 06:23:18 +03:00
struct ipv6_txoptions * ipv6_fixup_options ( struct ipv6_txoptions * opt_space ,
struct ipv6_txoptions * opt ) ;
2005-04-17 02:20:36 +04:00
2012-05-18 10:14:11 +04:00
extern bool ipv6_opt_accepted ( const struct sock * sk , const struct sk_buff * skb ) ;
2005-12-14 10:24:28 +03:00
2012-11-30 14:25:59 +04:00
static inline bool ipv6_accept_ra ( struct inet6_dev * idev )
{
/* If forwarding is enabled, RA are not accepted unless the special
* hybrid mode ( accept_ra = 2 ) is enabled .
*/
return idev - > cnf . forwarding ? idev - > cnf . accept_ra = = 2 :
idev - > cnf . accept_ra ;
}
2012-09-18 20:50:10 +04:00
# if IS_ENABLED(CONFIG_IPV6)
static inline int ip6_frag_nqueues ( struct net * net )
{
return net - > ipv6 . frags . nqueues ;
}
static inline int ip6_frag_mem ( struct net * net )
{
return atomic_read ( & net - > ipv6 . frags . mem ) ;
}
# endif
2005-04-17 02:20:36 +04:00
2010-02-16 21:40:04 +03:00
# define IPV6_FRAG_HIGH_THRESH (256 * 1024) /* 262144 */
# define IPV6_FRAG_LOW_THRESH (192 * 1024) /* 196608 */
# define IPV6_FRAG_TIMEOUT (60 * HZ) /* 60 seconds */
2005-04-17 02:20:36 +04:00
2005-11-08 20:38:12 +03:00
extern int __ipv6_addr_type ( const struct in6_addr * addr ) ;
static inline int ipv6_addr_type ( const struct in6_addr * addr )
{
return __ipv6_addr_type ( addr ) & 0xffff ;
}
2005-04-17 02:20:36 +04:00
static inline int ipv6_addr_scope ( const struct in6_addr * addr )
{
2005-11-08 20:38:12 +03:00
return __ipv6_addr_type ( addr ) & IPV6_ADDR_SCOPE_MASK ;
}
static inline int __ipv6_addr_src_scope ( int type )
{
2010-09-23 00:43:57 +04:00
return ( type = = IPV6_ADDR_ANY ) ? __IPV6_ADDR_SCOPE_INVALID : ( type > > 16 ) ;
2005-11-08 20:38:12 +03:00
}
static inline int ipv6_addr_src_scope ( const struct in6_addr * addr )
{
return __ipv6_addr_src_scope ( __ipv6_addr_type ( addr ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline int ipv6_addr_cmp ( const struct in6_addr * a1 , const struct in6_addr * a2 )
{
2007-05-04 04:39:04 +04:00
return memcmp ( a1 , a2 , sizeof ( struct in6_addr ) ) ;
2005-04-17 02:20:36 +04:00
}
2012-07-10 23:05:57 +04:00
static inline bool
2006-03-21 05:03:16 +03:00
ipv6_masked_addr_cmp ( const struct in6_addr * a1 , const struct in6_addr * m ,
const struct in6_addr * a2 )
{
2012-07-10 23:05:57 +04:00
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
const unsigned long * ul1 = ( const unsigned long * ) a1 ;
const unsigned long * ulm = ( const unsigned long * ) m ;
const unsigned long * ul2 = ( const unsigned long * ) a2 ;
return ! ! ( ( ( ul1 [ 0 ] ^ ul2 [ 0 ] ) & ulm [ 0 ] ) |
( ( ul1 [ 1 ] ^ ul2 [ 1 ] ) & ulm [ 1 ] ) ) ;
# else
2010-09-23 00:43:57 +04:00
return ! ! ( ( ( a1 - > s6_addr32 [ 0 ] ^ a2 - > s6_addr32 [ 0 ] ) & m - > s6_addr32 [ 0 ] ) |
( ( a1 - > s6_addr32 [ 1 ] ^ a2 - > s6_addr32 [ 1 ] ) & m - > s6_addr32 [ 1 ] ) |
( ( a1 - > s6_addr32 [ 2 ] ^ a2 - > s6_addr32 [ 2 ] ) & m - > s6_addr32 [ 2 ] ) |
( ( a1 - > s6_addr32 [ 3 ] ^ a2 - > s6_addr32 [ 3 ] ) & m - > s6_addr32 [ 3 ] ) ) ;
2012-07-10 23:05:57 +04:00
# endif
2006-03-21 05:03:16 +03:00
}
2005-04-17 02:20:36 +04:00
static inline void ipv6_addr_prefix ( struct in6_addr * pfx ,
const struct in6_addr * addr ,
int plen )
{
/* caller must guarantee 0 <= plen <= 128 */
int o = plen > > 3 ,
b = plen & 0x7 ;
2007-05-04 04:39:04 +04:00
memset ( pfx - > s6_addr , 0 , sizeof ( pfx - > s6_addr ) ) ;
2005-04-17 02:20:36 +04:00
memcpy ( pfx - > s6_addr , addr , o ) ;
2007-05-04 04:39:04 +04:00
if ( b ! = 0 )
2005-04-17 02:20:36 +04:00
pfx - > s6_addr [ o ] = addr - > s6_addr [ o ] & ( 0xff00 > > b ) ;
}
static inline void ipv6_addr_set ( struct in6_addr * addr ,
2006-09-28 05:44:54 +04:00
__be32 w1 , __be32 w2 ,
__be32 w3 , __be32 w4 )
2005-04-17 02:20:36 +04:00
{
addr - > s6_addr32 [ 0 ] = w1 ;
addr - > s6_addr32 [ 1 ] = w2 ;
addr - > s6_addr32 [ 2 ] = w3 ;
addr - > s6_addr32 [ 3 ] = w4 ;
}
2012-05-18 10:14:11 +04:00
static inline bool ipv6_addr_equal ( const struct in6_addr * a1 ,
const struct in6_addr * a2 )
2005-04-17 02:20:36 +04:00
{
2012-07-10 23:05:57 +04:00
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
const unsigned long * ul1 = ( const unsigned long * ) a1 ;
const unsigned long * ul2 = ( const unsigned long * ) a2 ;
return ( ( ul1 [ 0 ] ^ ul2 [ 0 ] ) | ( ul1 [ 1 ] ^ ul2 [ 1 ] ) ) = = 0UL ;
# else
2010-09-23 00:43:57 +04:00
return ( ( a1 - > s6_addr32 [ 0 ] ^ a2 - > s6_addr32 [ 0 ] ) |
( a1 - > s6_addr32 [ 1 ] ^ a2 - > s6_addr32 [ 1 ] ) |
( a1 - > s6_addr32 [ 2 ] ^ a2 - > s6_addr32 [ 2 ] ) |
( a1 - > s6_addr32 [ 3 ] ^ a2 - > s6_addr32 [ 3 ] ) ) = = 0 ;
2012-07-10 23:05:57 +04:00
# endif
2005-04-17 02:20:36 +04:00
}
2012-05-18 10:14:11 +04:00
static inline bool __ipv6_prefix_equal ( const __be32 * a1 , const __be32 * a2 ,
unsigned int prefixlen )
2005-04-17 02:20:36 +04:00
{
2012-04-15 09:58:06 +04:00
unsigned int pdw , pbi ;
2005-04-17 02:20:36 +04:00
/* check complete u32 in prefix */
pdw = prefixlen > > 5 ;
if ( pdw & & memcmp ( a1 , a2 , pdw < < 2 ) )
2012-05-18 10:14:11 +04:00
return false ;
2005-04-17 02:20:36 +04:00
/* check incomplete u32 in prefix */
pbi = prefixlen & 0x1f ;
if ( pbi & & ( ( a1 [ pdw ] ^ a2 [ pdw ] ) & htonl ( ( 0xffffffff ) < < ( 32 - pbi ) ) ) )
2012-05-18 10:14:11 +04:00
return false ;
2005-04-17 02:20:36 +04:00
2012-05-18 10:14:11 +04:00
return true ;
2005-04-17 02:20:36 +04:00
}
2012-05-18 10:14:11 +04:00
static inline bool ipv6_prefix_equal ( const struct in6_addr * a1 ,
const struct in6_addr * a2 ,
unsigned int prefixlen )
2005-04-17 02:20:36 +04:00
{
return __ipv6_prefix_equal ( a1 - > s6_addr32 , a2 - > s6_addr32 ,
prefixlen ) ;
}
2007-10-18 06:44:34 +04:00
struct inet_frag_queue ;
2009-12-15 18:59:18 +03:00
enum ip6_defrag_users {
IP6_DEFRAG_LOCAL_DELIVER ,
IP6_DEFRAG_CONNTRACK_IN ,
2010-05-25 01:33:03 +04:00
__IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX ,
2009-12-15 18:59:18 +03:00
IP6_DEFRAG_CONNTRACK_OUT ,
2010-05-25 01:33:03 +04:00
__IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX ,
2009-12-15 18:59:59 +03:00
IP6_DEFRAG_CONNTRACK_BRIDGE_IN ,
2010-05-25 01:33:03 +04:00
__IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX ,
2009-12-15 18:59:18 +03:00
} ;
2007-10-18 06:46:47 +04:00
struct ip6_create_arg {
__be32 id ;
2009-12-15 18:59:18 +03:00
u32 user ;
2011-04-22 08:53:02 +04:00
const struct in6_addr * src ;
const struct in6_addr * dst ;
2007-10-18 06:46:47 +04:00
} ;
void ip6_frag_init ( struct inet_frag_queue * q , void * a ) ;
2012-05-18 07:57:13 +04:00
bool ip6_frag_match ( struct inet_frag_queue * q , void * a ) ;
2007-10-18 06:46:47 +04:00
2012-09-18 20:50:09 +04:00
/*
* Equivalent of ipv4 struct ip
*/
struct frag_queue {
struct inet_frag_queue q ;
__be32 id ; /* fragment id */
u32 user ;
struct in6_addr saddr ;
struct in6_addr daddr ;
int iif ;
unsigned int csum ;
__u16 nhoffset ;
} ;
void ip6_expire_frag_queue ( struct net * net , struct frag_queue * fq ,
struct inet_frags * frags ) ;
2012-05-18 10:14:11 +04:00
static inline bool ipv6_addr_any ( const struct in6_addr * a )
2005-04-17 02:20:36 +04:00
{
2012-07-10 23:05:57 +04:00
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
const unsigned long * ul = ( const unsigned long * ) a ;
return ( ul [ 0 ] | ul [ 1 ] ) = = 0UL ;
# else
2010-09-23 00:43:57 +04:00
return ( a - > s6_addr32 [ 0 ] | a - > s6_addr32 [ 1 ] |
a - > s6_addr32 [ 2 ] | a - > s6_addr32 [ 3 ] ) = = 0 ;
2012-07-10 23:05:57 +04:00
# endif
2005-04-17 02:20:36 +04:00
}
2012-07-18 12:11:12 +04:00
static inline u32 ipv6_addr_hash ( const struct in6_addr * a )
{
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
const unsigned long * ul = ( const unsigned long * ) a ;
unsigned long x = ul [ 0 ] ^ ul [ 1 ] ;
return ( u32 ) ( x ^ ( x > > 32 ) ) ;
# else
return ( __force u32 ) ( a - > s6_addr32 [ 0 ] ^ a - > s6_addr32 [ 1 ] ^
a - > s6_addr32 [ 2 ] ^ a - > s6_addr32 [ 3 ] ) ;
# endif
}
2012-05-18 10:14:11 +04:00
static inline bool ipv6_addr_loopback ( const struct in6_addr * a )
2008-06-20 03:33:57 +04:00
{
2013-01-14 11:10:06 +04:00
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
const unsigned long * ul = ( const unsigned long * ) a ;
return ( ul [ 0 ] | ( ul [ 1 ] ^ cpu_to_be64 ( 1 ) ) ) = = 0UL ;
# else
2010-09-23 00:43:57 +04:00
return ( a - > s6_addr32 [ 0 ] | a - > s6_addr32 [ 1 ] |
a - > s6_addr32 [ 2 ] | ( a - > s6_addr32 [ 3 ] ^ htonl ( 1 ) ) ) = = 0 ;
2013-01-14 11:10:06 +04:00
# endif
2008-06-20 03:33:57 +04:00
}
2012-05-18 10:14:11 +04:00
static inline bool ipv6_addr_v4mapped ( const struct in6_addr * a )
2007-08-25 10:16:08 +04:00
{
2010-09-23 00:43:57 +04:00
return ( a - > s6_addr32 [ 0 ] | a - > s6_addr32 [ 1 ] |
( a - > s6_addr32 [ 2 ] ^ htonl ( 0x0000ffff ) ) ) = = 0 ;
2007-08-25 10:16:08 +04:00
}
2008-02-29 07:55:46 +03:00
/*
* Check for a RFC 4843 ORCHID address
* ( Overlay Routable Cryptographic Hash Identifiers )
*/
2012-05-18 10:14:11 +04:00
static inline bool ipv6_addr_orchid ( const struct in6_addr * a )
2008-02-29 07:55:46 +03:00
{
2010-09-23 00:43:57 +04:00
return ( a - > s6_addr32 [ 0 ] & htonl ( 0xfffffff0 ) ) = = htonl ( 0x20010010 ) ;
2008-02-29 07:55:46 +03:00
}
2008-01-18 17:50:56 +03:00
static inline void ipv6_addr_set_v4mapped ( const __be32 addr ,
struct in6_addr * v4mapped )
{
ipv6_addr_set ( v4mapped ,
0 , 0 ,
htonl ( 0x0000FFFF ) ,
addr ) ;
}
2005-11-08 20:37:56 +03:00
/*
* find the first different bit between two addresses
* length of address must be a multiple of 32 bits
*/
2013-01-14 11:09:54 +04:00
static inline int __ipv6_addr_diff32 ( const void * token1 , const void * token2 , int addrlen )
2005-11-08 20:37:56 +03:00
{
2006-11-15 07:56:33 +03:00
const __be32 * a1 = token1 , * a2 = token2 ;
2005-11-08 20:37:56 +03:00
int i ;
addrlen > > = 2 ;
for ( i = 0 ; i < addrlen ; i + + ) {
2006-11-15 07:56:33 +03:00
__be32 xb = a1 [ i ] ^ a2 [ i ] ;
if ( xb )
2010-03-29 10:00:05 +04:00
return i * 32 + 31 - __fls ( ntohl ( xb ) ) ;
2005-11-08 20:37:56 +03:00
}
/*
* we should * never * get to this point since that
* would mean the addrs are equal
*
* However , we do get to it 8 ) And exacly , when
* addresses are equal 8 )
*
* ip route add 1111 : : / 128 via . . .
* ip route add 1111 : : / 64 via . . .
* and we are here .
*
* Ideally , this function should stop comparison
* at prefix length . It does not , but it is still OK ,
* if returned value is greater than prefix length .
* - - ANK ( 980803 )
*/
2010-09-23 00:43:57 +04:00
return addrlen < < 5 ;
2005-11-08 20:37:56 +03:00
}
2013-01-14 11:09:54 +04:00
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
static inline int __ipv6_addr_diff64 ( const void * token1 , const void * token2 , int addrlen )
{
const __be64 * a1 = token1 , * a2 = token2 ;
int i ;
addrlen > > = 3 ;
for ( i = 0 ; i < addrlen ; i + + ) {
__be64 xb = a1 [ i ] ^ a2 [ i ] ;
if ( xb )
return i * 64 + 63 - __fls ( be64_to_cpu ( xb ) ) ;
}
return addrlen < < 6 ;
}
# endif
static inline int __ipv6_addr_diff ( const void * token1 , const void * token2 , int addrlen )
{
# if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
if ( __builtin_constant_p ( addrlen ) & & ! ( addrlen & 7 ) )
return __ipv6_addr_diff64 ( token1 , token2 , addrlen ) ;
# endif
return __ipv6_addr_diff32 ( token1 , token2 , addrlen ) ;
}
2005-11-08 20:37:56 +03:00
static inline int ipv6_addr_diff ( const struct in6_addr * a1 , const struct in6_addr * a2 )
{
return __ipv6_addr_diff ( a1 , a2 , sizeof ( struct in6_addr ) ) ;
}
2011-07-22 08:25:58 +04:00
extern void ipv6_select_ident ( struct frag_hdr * fhdr , struct rt6_info * rt ) ;
2009-07-09 12:10:01 +04:00
2013-01-13 09:01:39 +04:00
/*
* Header manipulation
*/
static inline void ip6_flow_hdr ( struct ipv6hdr * hdr , unsigned int tclass ,
__be32 flowlabel )
{
* ( __be32 * ) hdr = ntohl ( 0x60000000 | ( tclass < < 20 ) ) | flowlabel ;
}
2013-01-13 09:01:51 +04:00
static inline __be32 ip6_flowinfo ( const struct ipv6hdr * hdr )
{
return * ( __be32 * ) hdr & IPV6_FLOWINFO_MASK ;
}
2005-04-17 02:20:36 +04:00
/*
* Prototypes exported by ipv6
*/
/*
* rcv function ( called from netdevice level )
*/
extern int ipv6_rcv ( struct sk_buff * skb ,
struct net_device * dev ,
2005-08-10 06:34:12 +04:00
struct packet_type * pt ,
struct net_device * orig_dev ) ;
2005-04-17 02:20:36 +04:00
2006-01-07 10:03:34 +03:00
extern int ip6_rcv_finish ( struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
/*
* upper - layer output functions
*/
extern int ip6_xmit ( struct sock * sk ,
struct sk_buff * skb ,
2011-03-13 00:22:43 +03:00
struct flowi6 * fl6 ,
2011-10-27 08:44:35 +04:00
struct ipv6_txoptions * opt ,
int tclass ) ;
2005-04-17 02:20:36 +04:00
extern int ip6_nd_hdr ( struct sock * sk ,
struct sk_buff * skb ,
struct net_device * dev ,
[IPV6]: Make address arguments const.
- net/ipv6/addrconf.c:
ipv6_get_ifaddr(), ipv6_dev_get_saddr()
- net/ipv6/mcast.c:
ipv6_sock_mc_join(), ipv6_sock_mc_drop(),
inet6_mc_check(),
ipv6_dev_mc_inc(), __ipv6_dev_mc_dec(), ipv6_dev_mc_dec(),
ipv6_chk_mcast_addr()
- net/ipv6/route.c:
rt6_lookup(), icmp6_dst_alloc()
- net/ipv6/ip6_output.c:
ip6_nd_hdr()
- net/ipv6/ndisc.c:
ndisc_send_ns(), ndisc_send_rs(), ndisc_send_redirect(),
ndisc_get_neigh(), __ndisc_send()
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2008-04-10 10:42:10 +04:00
const struct in6_addr * saddr ,
const struct in6_addr * daddr ,
2005-04-17 02:20:36 +04:00
int proto , int len ) ;
extern int ip6_find_1stfragopt ( struct sk_buff * skb , u8 * * nexthdr ) ;
extern int ip6_append_data ( struct sock * sk ,
int getfrag ( void * from , char * to , int offset , int len , int odd , struct sk_buff * skb ) ,
void * from ,
int length ,
int transhdrlen ,
int hlimit ,
2005-09-08 05:19:03 +04:00
int tclass ,
2005-04-17 02:20:36 +04:00
struct ipv6_txoptions * opt ,
2011-03-13 00:22:43 +03:00
struct flowi6 * fl6 ,
2005-04-17 02:20:36 +04:00
struct rt6_info * rt ,
2010-04-23 15:26:08 +04:00
unsigned int flags ,
int dontfrag ) ;
2005-04-17 02:20:36 +04:00
extern int ip6_push_pending_frames ( struct sock * sk ) ;
extern void ip6_flush_pending_frames ( struct sock * sk ) ;
extern int ip6_dst_lookup ( struct sock * sk ,
struct dst_entry * * dst ,
2011-03-13 00:22:43 +03:00
struct flowi6 * fl6 ) ;
2011-03-02 00:19:07 +03:00
extern struct dst_entry * ip6_dst_lookup_flow ( struct sock * sk ,
2011-03-13 00:22:43 +03:00
struct flowi6 * fl6 ,
2011-03-02 00:19:07 +03:00
const struct in6_addr * final_dst ,
2011-03-02 01:32:04 +03:00
bool can_sleep ) ;
2011-03-02 00:19:07 +03:00
extern struct dst_entry * ip6_sk_dst_lookup_flow ( struct sock * sk ,
2011-03-13 00:22:43 +03:00
struct flowi6 * fl6 ,
2011-03-02 00:19:07 +03:00
const struct in6_addr * final_dst ,
2011-03-02 01:32:04 +03:00
bool can_sleep ) ;
2011-03-02 01:59:04 +03:00
extern struct dst_entry * ip6_blackhole_route ( struct net * net ,
struct dst_entry * orig_dst ) ;
2005-04-17 02:20:36 +04:00
/*
* skb processing functions
*/
extern int ip6_output ( struct sk_buff * skb ) ;
extern int ip6_forward ( struct sk_buff * skb ) ;
extern int ip6_input ( struct sk_buff * skb ) ;
extern int ip6_mc_input ( struct sk_buff * skb ) ;
2008-01-12 06:15:08 +03:00
extern int __ip6_local_out ( struct sk_buff * skb ) ;
extern int ip6_local_out ( struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
/*
* Extension header ( options ) processing
*/
extern void ipv6_push_nfrag_opts ( struct sk_buff * skb ,
struct ipv6_txoptions * opt ,
u8 * proto ,
struct in6_addr * * daddr_p ) ;
extern void ipv6_push_frag_opts ( struct sk_buff * skb ,
struct ipv6_txoptions * opt ,
u8 * proto ) ;
extern int ipv6_skip_exthdr ( const struct sk_buff * , int start ,
2011-12-01 05:05:51 +04:00
u8 * nexthdrp , __be16 * frag_offp ) ;
2005-04-17 02:20:36 +04:00
2012-05-18 22:57:34 +04:00
extern bool ipv6_ext_hdr ( u8 nexthdr ) ;
2005-04-17 02:20:36 +04:00
2012-11-10 05:05:07 +04:00
enum {
2012-11-10 05:11:31 +04:00
IP6_FH_F_FRAG = ( 1 < < 0 ) ,
IP6_FH_F_AUTH = ( 1 < < 1 ) ,
IP6_FH_F_SKIP_RH = ( 1 < < 2 ) ,
2012-11-10 05:05:07 +04:00
} ;
/* find specified header and get offset to it */
extern int ipv6_find_hdr ( const struct sk_buff * skb , unsigned int * offset ,
int target , unsigned short * fragoff , int * fragflg ) ;
2006-08-24 06:18:35 +04:00
extern int ipv6_find_tlv ( struct sk_buff * skb , int offset , int type ) ;
2011-03-13 00:22:43 +03:00
extern struct in6_addr * fl6_update_dst ( struct flowi6 * fl6 ,
2010-06-02 01:35:01 +04:00
const struct ipv6_txoptions * opt ,
struct in6_addr * orig ) ;
2005-04-17 02:20:36 +04:00
/*
* socket options ( ipv6_sockglue . c )
*/
extern int ipv6_setsockopt ( struct sock * sk , int level ,
int optname ,
char __user * optval ,
2009-10-01 03:12:20 +04:00
unsigned int optlen ) ;
2005-04-17 02:20:36 +04:00
extern int ipv6_getsockopt ( struct sock * sk , int level ,
int optname ,
char __user * optval ,
int __user * optlen ) ;
2006-03-21 09:45:21 +03:00
extern int compat_ipv6_setsockopt ( struct sock * sk ,
int level ,
int optname ,
char __user * optval ,
2009-10-01 03:12:20 +04:00
unsigned int optlen ) ;
2006-03-21 09:45:21 +03:00
extern int compat_ipv6_getsockopt ( struct sock * sk ,
int level ,
int optname ,
char __user * optval ,
int __user * optlen ) ;
2005-04-17 02:20:36 +04:00
extern int ip6_datagram_connect ( struct sock * sk ,
struct sockaddr * addr , int addr_len ) ;
extern int ipv6_recv_error ( struct sock * sk , struct msghdr * msg , int len ) ;
2010-04-23 15:26:09 +04:00
extern int ipv6_recv_rxpmtu ( struct sock * sk , struct msghdr * msg , int len ) ;
2006-11-15 07:56:00 +03:00
extern void ipv6_icmp_error ( struct sock * sk , struct sk_buff * skb , int err , __be16 port ,
2005-04-17 02:20:36 +04:00
u32 info , u8 * payload ) ;
2011-03-13 00:22:43 +03:00
extern void ipv6_local_error ( struct sock * sk , int err , struct flowi6 * fl6 , u32 info ) ;
extern void ipv6_local_rxpmtu ( struct sock * sk , struct flowi6 * fl6 , u32 mtu ) ;
2005-04-17 02:20:36 +04:00
extern int inet6_release ( struct socket * sock ) ;
extern int inet6_bind ( struct socket * sock , struct sockaddr * uaddr ,
int addr_len ) ;
extern int inet6_getname ( struct socket * sock , struct sockaddr * uaddr ,
int * uaddr_len , int peer ) ;
extern int inet6_ioctl ( struct socket * sock , unsigned int cmd ,
unsigned long arg ) ;
2005-12-14 10:25:44 +03:00
extern int inet6_hash_connect ( struct inet_timewait_death_row * death_row ,
struct sock * sk ) ;
2005-04-17 02:20:36 +04:00
/*
* reassembly . c
*/
2005-12-22 23:49:22 +03:00
extern const struct proto_ops inet6_stream_ops ;
extern const struct proto_ops inet6_dgram_ops ;
2005-08-16 09:18:02 +04:00
2005-12-27 07:43:12 +03:00
struct group_source_req ;
struct group_filter ;
2005-08-16 09:18:02 +04:00
extern int ip6_mc_source ( int add , int omode , struct sock * sk ,
struct group_source_req * pgsr ) ;
extern int ip6_mc_msfilter ( struct sock * sk , struct group_filter * gsf ) ;
extern int ip6_mc_msfget ( struct sock * sk , struct group_filter * gsf ,
struct group_filter __user * optval ,
int __user * optlen ) ;
ipv6: almost identical frag hashing funcs combined
$ diff-funcs ip6qhashfn reassembly.c netfilter/nf_conntrack_reasm.c
--- reassembly.c:ip6qhashfn()
+++ netfilter/nf_conntrack_reasm.c:ip6qhashfn()
@@ -1,5 +1,5 @@
-static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
- struct in6_addr *daddr)
+static unsigned int ip6qhashfn(__be32 id, const struct in6_addr *saddr,
+ const struct in6_addr *daddr)
{
u32 a, b, c;
@@ -9,7 +9,7 @@
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
- c += ip6_frags.rnd;
+ c += nf_frags.rnd;
__jhash_mix(a, b, c);
a += (__force u32)saddr->s6_addr32[3];
And codiff xx.o.old xx.o.new:
net/ipv6/netfilter/nf_conntrack_reasm.c:
ip6qhashfn | -512
nf_hashfn | +6
nf_ct_frag6_gather | +36
3 functions changed, 42 bytes added, 512 bytes removed, diff: -470
net/ipv6/reassembly.c:
ip6qhashfn | -512
ip6_hashfn | +7
ipv6_frag_rcv | +89
3 functions changed, 96 bytes added, 512 bytes removed, diff: -416
net/ipv6/reassembly.c:
inet6_hash_frag | +510
1 function changed, 510 bytes added, diff: +510
Total: -376
Compile tested.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-10-01 13:48:31 +04:00
extern unsigned int inet6_hash_frag ( __be32 id , const struct in6_addr * saddr ,
const struct in6_addr * daddr , u32 rnd ) ;
2005-08-16 09:18:02 +04:00
# ifdef CONFIG_PROC_FS
2008-03-27 02:52:32 +03:00
extern int ac6_proc_init ( struct net * net ) ;
extern void ac6_proc_exit ( struct net * net ) ;
2005-08-16 09:18:02 +04:00
extern int raw6_proc_init ( void ) ;
extern void raw6_proc_exit ( void ) ;
2008-03-21 14:14:45 +03:00
extern int tcp6_proc_init ( struct net * net ) ;
extern void tcp6_proc_exit ( struct net * net ) ;
2008-03-21 14:14:17 +03:00
extern int udp6_proc_init ( struct net * net ) ;
extern void udp6_proc_exit ( struct net * net ) ;
2006-11-27 22:10:57 +03:00
extern int udplite6_proc_init ( void ) ;
extern void udplite6_proc_exit ( void ) ;
2005-08-16 09:18:02 +04:00
extern int ipv6_misc_proc_init ( void ) ;
extern void ipv6_misc_proc_exit ( void ) ;
2007-04-25 08:54:09 +04:00
extern int snmp6_register_dev ( struct inet6_dev * idev ) ;
extern int snmp6_unregister_dev ( struct inet6_dev * idev ) ;
2005-08-16 09:18:02 +04:00
2007-04-25 08:54:09 +04:00
# else
2008-03-27 02:52:32 +03:00
static inline int ac6_proc_init ( struct net * net ) { return 0 ; }
static inline void ac6_proc_exit ( struct net * net ) { }
static inline int snmp6_register_dev ( struct inet6_dev * idev ) { return 0 ; }
static inline int snmp6_unregister_dev ( struct inet6_dev * idev ) { return 0 ; }
2005-08-16 09:18:02 +04:00
# endif
2005-04-17 02:20:36 +04:00
2005-08-16 09:18:02 +04:00
# ifdef CONFIG_SYSCTL
2008-01-10 13:53:43 +03:00
extern ctl_table ipv6_route_table_template [ ] ;
extern ctl_table ipv6_icmp_table_template [ ] ;
2005-04-17 02:20:36 +04:00
2008-02-05 13:57:59 +03:00
extern struct ctl_table * ipv6_icmp_sysctl_init ( struct net * net ) ;
extern struct ctl_table * ipv6_route_sysctl_init ( struct net * net ) ;
2008-01-10 13:47:55 +03:00
extern int ipv6_sysctl_register ( void ) ;
2005-08-16 09:18:02 +04:00
extern void ipv6_sysctl_unregister ( void ) ;
# endif
2005-04-17 02:20:36 +04:00
2005-08-16 09:18:02 +04:00
# endif /* _NET_IPV6_H */