diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 36 |
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 | ||
94 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); | 94 | static u32 ndisc_hash(const void *pkey, |
95 | const struct net_device *dev, | ||
96 | __u32 rnd); | ||
95 | static int ndisc_constructor(struct neighbour *neigh); | 97 | static int ndisc_constructor(struct neighbour *neigh); |
96 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 98 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
97 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); | 99 | static 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 | ||
234 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) | 236 | static 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 | ||
239 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | 241 | static 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 | ||
250 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | 252 | static 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 | ||
325 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) | 327 | int 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 | ||
351 | EXPORT_SYMBOL(ndisc_mc_map); | 353 | EXPORT_SYMBOL(ndisc_mc_map); |
352 | 354 | ||
353 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev) | 355 | static 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 | ||
365 | static int ndisc_constructor(struct neighbour *neigh) | 369 | static 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 | ||
1112 | static 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 | |||
1108 | static void ndisc_router_discovery(struct sk_buff *skb) | 1124 | static 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 |