2005-04-17 02:20:36 +04:00
# ifndef _NDISC_H
# define _NDISC_H
/*
* ICMP codes for neighbour discovery messages
*/
# define NDISC_ROUTER_SOLICITATION 133
# define NDISC_ROUTER_ADVERTISEMENT 134
# define NDISC_NEIGHBOUR_SOLICITATION 135
# define NDISC_NEIGHBOUR_ADVERTISEMENT 136
# define NDISC_REDIRECT 137
2008-03-12 01:35:59 +03:00
/*
* Router type : cross - layer information from link - layer to
* IPv6 layer reported by certain link types ( e . g . , RFC4214 ) .
*/
# define NDISC_NODETYPE_UNSPEC 0 /* unspecified (default) */
# define NDISC_NODETYPE_HOST 1 /* host or unauthorized router */
# define NDISC_NODETYPE_NODEFAULT 2 /* non-default router */
# define NDISC_NODETYPE_DEFAULT 3 /* default router */
2005-04-17 02:20:36 +04:00
/*
* ndisc options
*/
enum {
__ND_OPT_PREFIX_INFO_END = 0 ,
ND_OPT_SOURCE_LL_ADDR = 1 , /* RFC2461 */
ND_OPT_TARGET_LL_ADDR = 2 , /* RFC2461 */
ND_OPT_PREFIX_INFO = 3 , /* RFC2461 */
ND_OPT_REDIRECT_HDR = 4 , /* RFC2461 */
ND_OPT_MTU = 5 , /* RFC2461 */
2006-03-21 04:06:24 +03:00
__ND_OPT_ARRAY_MAX ,
ND_OPT_ROUTE_INFO = 24 , /* RFC4191 */
2007-10-11 08:22:05 +04:00
ND_OPT_RDNSS = 25 , /* RFC5006 */
2012-04-06 09:50:58 +04:00
ND_OPT_DNSSL = 31 , /* RFC6106 */
2005-04-17 02:20:36 +04:00
__ND_OPT_MAX
} ;
# define MAX_RTR_SOLICITATION_DELAY HZ
# define ND_REACHABLE_TIME (30*HZ)
# define ND_RETRANS_TIMER HZ
2005-12-27 07:43:12 +03:00
# include <linux/compiler.h>
2005-04-17 02:20:36 +04:00
# include <linux/icmpv6.h>
2005-12-27 07:43:12 +03:00
# include <linux/in6.h>
# include <linux/types.h>
2012-07-12 10:26:46 +04:00
# include <linux/if_arp.h>
# include <linux/netdevice.h>
2012-08-09 01:52:28 +04:00
# include <linux/hash.h>
2005-12-27 07:43:12 +03:00
2005-04-17 02:20:36 +04:00
# include <net/neighbour.h>
2005-12-27 07:43:12 +03:00
struct ctl_table ;
struct inet6_dev ;
struct net_device ;
struct net_proto_family ;
struct sk_buff ;
2005-04-17 02:20:36 +04:00
extern struct neigh_table nd_tbl ;
struct nd_msg {
struct icmp6hdr icmph ;
struct in6_addr target ;
__u8 opt [ 0 ] ;
} ;
struct rs_msg {
struct icmp6hdr icmph ;
__u8 opt [ 0 ] ;
} ;
struct ra_msg {
struct icmp6hdr icmph ;
2006-11-15 07:56:00 +03:00
__be32 reachable_time ;
__be32 retrans_timer ;
2005-04-17 02:20:36 +04:00
} ;
2012-12-14 06:59:59 +04:00
struct rd_msg {
struct icmp6hdr icmph ;
struct in6_addr target ;
struct in6_addr dest ;
__u8 opt [ 0 ] ;
} ;
2005-04-17 02:20:36 +04:00
struct nd_opt_hdr {
__u8 nd_opt_type ;
__u8 nd_opt_len ;
2010-06-03 14:21:52 +04:00
} __packed ;
2005-04-17 02:20:36 +04:00
2012-07-12 10:26:46 +04:00
/* ND options */
struct ndisc_options {
struct nd_opt_hdr * nd_opt_array [ __ND_OPT_ARRAY_MAX ] ;
# ifdef CONFIG_IPV6_ROUTE_INFO
struct nd_opt_hdr * nd_opts_ri ;
struct nd_opt_hdr * nd_opts_ri_end ;
# endif
struct nd_opt_hdr * nd_useropts ;
struct nd_opt_hdr * nd_useropts_end ;
} ;
# define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
# define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR]
# define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO]
# define nd_opts_pi_end nd_opt_array[__ND_OPT_PREFIX_INFO_END]
# define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
# define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
# define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
2013-09-21 21:22:47 +04:00
struct ndisc_options * ndisc_parse_options ( u8 * opt , int opt_len ,
struct ndisc_options * ndopts ) ;
2012-07-12 10:26:46 +04:00
/*
* Return the padding between the option length and the start of the
* link addr . Currently only IP - over - InfiniBand needs this , although
* if RFC 3831 IPv6 - over - Fibre Channel is ever implemented it may
* also need a pad of 2.
*/
2013-07-30 21:31:00 +04:00
static inline int ndisc_addr_option_pad ( unsigned short type )
2012-07-12 10:26:46 +04:00
{
switch ( type ) {
case ARPHRD_INFINIBAND : return 2 ;
default : return 0 ;
}
}
2013-01-21 10:47:56 +04:00
static inline int ndisc_opt_addr_space ( struct net_device * dev )
{
return NDISC_OPT_SPACE ( dev - > addr_len +
ndisc_addr_option_pad ( dev - > type ) ) ;
}
2012-07-12 10:26:46 +04:00
static inline u8 * ndisc_opt_addr_data ( struct nd_opt_hdr * p ,
struct net_device * dev )
{
u8 * lladdr = ( u8 * ) ( p + 1 ) ;
int lladdrlen = p - > nd_opt_len < < 3 ;
int prepad = ndisc_addr_option_pad ( dev - > type ) ;
2013-01-21 10:47:56 +04:00
if ( lladdrlen ! = ndisc_opt_addr_space ( dev ) )
2012-07-12 10:26:46 +04:00
return NULL ;
return lladdr + prepad ;
}
2011-12-29 00:06:58 +04:00
static inline u32 ndisc_hashfn ( const void * pkey , const struct net_device * dev , __u32 * hash_rnd )
{
const u32 * p32 = pkey ;
2012-08-09 01:52:28 +04:00
return ( ( ( p32 [ 0 ] ^ hash32_ptr ( dev ) ) * hash_rnd [ 0 ] ) +
2011-12-29 00:06:58 +04:00
( p32 [ 1 ] * hash_rnd [ 1 ] ) +
( p32 [ 2 ] * hash_rnd [ 2 ] ) +
( p32 [ 3 ] * hash_rnd [ 3 ] ) ) ;
}
2005-04-17 02:20:36 +04:00
2013-01-17 16:53:22 +04:00
static inline struct neighbour * __ipv6_neigh_lookup_noref ( struct net_device * dev , const void * pkey )
2011-12-29 00:41:23 +04:00
{
struct neigh_hash_table * nht ;
const u32 * p32 = pkey ;
struct neighbour * n ;
u32 hash_val ;
2013-01-17 16:53:09 +04:00
nht = rcu_dereference_bh ( nd_tbl . nht ) ;
2011-12-29 00:41:23 +04:00
hash_val = ndisc_hashfn ( pkey , dev , nht - > hash_rnd ) > > ( 32 - nht - > hash_shift ) ;
for ( n = rcu_dereference_bh ( nht - > hash_buckets [ hash_val ] ) ;
n ! = NULL ;
n = rcu_dereference_bh ( n - > next ) ) {
u32 * n32 = ( u32 * ) n - > primary_key ;
if ( n - > dev = = dev & &
( ( n32 [ 0 ] ^ p32 [ 0 ] ) | ( n32 [ 1 ] ^ p32 [ 1 ] ) |
2013-01-17 16:53:22 +04:00
( n32 [ 2 ] ^ p32 [ 2 ] ) | ( n32 [ 3 ] ^ p32 [ 3 ] ) ) = = 0 )
return n ;
2011-12-29 00:41:23 +04:00
}
2013-01-17 16:53:22 +04:00
return NULL ;
}
static inline struct neighbour * __ipv6_neigh_lookup ( struct net_device * dev , const void * pkey )
{
struct neighbour * n ;
rcu_read_lock_bh ( ) ;
n = __ipv6_neigh_lookup_noref ( dev , pkey ) ;
if ( n & & ! atomic_inc_not_zero ( & n - > refcnt ) )
n = NULL ;
2011-12-29 00:41:23 +04:00
rcu_read_unlock_bh ( ) ;
return n ;
}
2013-09-21 21:22:47 +04:00
int ndisc_init ( void ) ;
int ndisc_late_init ( void ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
void ndisc_late_cleanup ( void ) ;
void ndisc_cleanup ( void ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
int ndisc_rcv ( struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
void ndisc_send_ns ( struct net_device * dev , struct neighbour * neigh ,
const struct in6_addr * solicit ,
const struct in6_addr * daddr , const struct in6_addr * saddr ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
void ndisc_send_rs ( struct net_device * dev ,
const struct in6_addr * saddr , const struct in6_addr * daddr ) ;
void ndisc_send_na ( struct net_device * dev , struct neighbour * neigh ,
const struct in6_addr * daddr ,
const struct in6_addr * solicited_addr ,
bool router , bool solicited , bool override , bool inc_opt ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
void ndisc_send_redirect ( struct sk_buff * skb , const struct in6_addr * target ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
int ndisc_mc_map ( const struct in6_addr * addr , char * buf , struct net_device * dev ,
int dir ) ;
2005-04-17 02:20:36 +04:00
/*
* IGMP
*/
2013-09-21 21:22:47 +04:00
int igmp6_init ( void ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
void igmp6_cleanup ( void ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
int igmp6_event_query ( struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
2013-09-21 21:22:47 +04:00
int igmp6_event_report ( struct sk_buff * skb ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SYSCTL
2013-09-21 21:22:47 +04:00
int ndisc_ifinfo_sysctl_change ( struct ctl_table * ctl , int write ,
void __user * buffer , size_t * lenp , loff_t * ppos ) ;
2013-06-14 06:37:54 +04:00
int ndisc_ifinfo_sysctl_strategy ( struct ctl_table * ctl ,
2008-10-16 09:04:23 +04:00
void __user * oldval , size_t __user * oldlenp ,
2008-05-20 03:25:42 +04:00
void __user * newval , size_t newlen ) ;
2005-04-17 02:20:36 +04:00
# endif
2013-09-21 21:22:47 +04:00
void inet6_ifinfo_notify ( int event , struct inet6_dev * idev ) ;
2005-04-17 02:20:36 +04:00
# endif