aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 58841c4ae947..998d6d27e7cf 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -91,7 +91,9 @@
91#include <linux/netfilter.h> 91#include <linux/netfilter.h>
92#include <linux/netfilter_ipv6.h> 92#include <linux/netfilter_ipv6.h>
93 93
94static u32 ndisc_hash(const void *pkey, const struct net_device *dev); 94static u32 ndisc_hash(const void *pkey,
95 const struct net_device *dev,
96 __u32 rnd);
95static int ndisc_constructor(struct neighbour *neigh); 97static int ndisc_constructor(struct neighbour *neigh);
96static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); 98static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
97static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); 99static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -228,12 +230,12 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
228 do { 230 do {
229 cur = ((void *)cur) + (cur->nd_opt_len << 3); 231 cur = ((void *)cur) + (cur->nd_opt_len << 3);
230 } while(cur < end && cur->nd_opt_type != type); 232 } while(cur < end && cur->nd_opt_type != type);
231 return (cur <= end && cur->nd_opt_type == type ? cur : NULL); 233 return cur <= end && cur->nd_opt_type == type ? cur : NULL;
232} 234}
233 235
234static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) 236static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
235{ 237{
236 return (opt->nd_opt_type == ND_OPT_RDNSS); 238 return opt->nd_opt_type == ND_OPT_RDNSS;
237} 239}
238 240
239static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, 241static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
@@ -244,7 +246,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
244 do { 246 do {
245 cur = ((void *)cur) + (cur->nd_opt_len << 3); 247 cur = ((void *)cur) + (cur->nd_opt_len << 3);
246 } while(cur < end && !ndisc_is_useropt(cur)); 248 } while(cur < end && !ndisc_is_useropt(cur));
247 return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL); 249 return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
248} 250}
249 251
250static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, 252static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
@@ -319,7 +321,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
319 int prepad = ndisc_addr_option_pad(dev->type); 321 int prepad = ndisc_addr_option_pad(dev->type);
320 if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) 322 if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad))
321 return NULL; 323 return NULL;
322 return (lladdr + prepad); 324 return lladdr + prepad;
323} 325}
324 326
325int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) 327int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
@@ -350,7 +352,9 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
350 352
351EXPORT_SYMBOL(ndisc_mc_map); 353EXPORT_SYMBOL(ndisc_mc_map);
352 354
353static u32 ndisc_hash(const void *pkey, const struct net_device *dev) 355static u32 ndisc_hash(const void *pkey,
356 const struct net_device *dev,
357 __u32 hash_rnd)
354{ 358{
355 const u32 *p32 = pkey; 359 const u32 *p32 = pkey;
356 u32 addr_hash, i; 360 u32 addr_hash, i;
@@ -359,7 +363,7 @@ static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
359 for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) 363 for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
360 addr_hash ^= *p32++; 364 addr_hash ^= *p32++;
361 365
362 return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd); 366 return jhash_2words(addr_hash, dev->ifindex, hash_rnd);
363} 367}
364 368
365static int ndisc_constructor(struct neighbour *neigh) 369static int ndisc_constructor(struct neighbour *neigh)
@@ -1105,6 +1109,18 @@ errout:
1105 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); 1109 rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
1106} 1110}
1107 1111
1112static inline int accept_ra(struct inet6_dev *in6_dev)
1113{
1114 /*
1115 * If forwarding is enabled, RA are not accepted unless the special
1116 * hybrid mode (accept_ra=2) is enabled.
1117 */
1118 if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2)
1119 return 0;
1120
1121 return in6_dev->cnf.accept_ra;
1122}
1123
1108static void ndisc_router_discovery(struct sk_buff *skb) 1124static void ndisc_router_discovery(struct sk_buff *skb)
1109{ 1125{
1110 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); 1126 struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
@@ -1158,8 +1174,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1158 return; 1174 return;
1159 } 1175 }
1160 1176
1161 /* skip route and link configuration on routers */ 1177 if (!accept_ra(in6_dev))
1162 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
1163 goto skip_linkparms; 1178 goto skip_linkparms;
1164 1179
1165#ifdef CONFIG_IPV6_NDISC_NODETYPE 1180#ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1309,8 +1324,7 @@ skip_linkparms:
1309 NEIGH_UPDATE_F_ISROUTER); 1324 NEIGH_UPDATE_F_ISROUTER);
1310 } 1325 }
1311 1326
1312 /* skip route and link configuration on routers */ 1327 if (!accept_ra(in6_dev))
1313 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
1314 goto out; 1328 goto out;
1315 1329
1316#ifdef CONFIG_IPV6_ROUTE_INFO 1330#ifdef CONFIG_IPV6_ROUTE_INFO