diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c14ea1ecf379..0f56e9e69a8f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -308,6 +308,46 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static int ip6_forward_proxy_check(struct sk_buff *skb) | ||
312 | { | ||
313 | struct ipv6hdr *hdr = skb->nh.ipv6h; | ||
314 | u8 nexthdr = hdr->nexthdr; | ||
315 | int offset; | ||
316 | |||
317 | if (ipv6_ext_hdr(nexthdr)) { | ||
318 | offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr); | ||
319 | if (offset < 0) | ||
320 | return 0; | ||
321 | } else | ||
322 | offset = sizeof(struct ipv6hdr); | ||
323 | |||
324 | if (nexthdr == IPPROTO_ICMPV6) { | ||
325 | struct icmp6hdr *icmp6; | ||
326 | |||
327 | if (!pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) | ||
328 | return 0; | ||
329 | |||
330 | icmp6 = (struct icmp6hdr *)(skb->nh.raw + offset); | ||
331 | |||
332 | switch (icmp6->icmp6_type) { | ||
333 | case NDISC_ROUTER_SOLICITATION: | ||
334 | case NDISC_ROUTER_ADVERTISEMENT: | ||
335 | case NDISC_NEIGHBOUR_SOLICITATION: | ||
336 | case NDISC_NEIGHBOUR_ADVERTISEMENT: | ||
337 | case NDISC_REDIRECT: | ||
338 | /* For reaction involving unicast neighbor discovery | ||
339 | * message destined to the proxied address, pass it to | ||
340 | * input function. | ||
341 | */ | ||
342 | return 1; | ||
343 | default: | ||
344 | break; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
311 | static inline int ip6_forward_finish(struct sk_buff *skb) | 351 | static inline int ip6_forward_finish(struct sk_buff *skb) |
312 | { | 352 | { |
313 | return dst_output(skb); | 353 | return dst_output(skb); |
@@ -362,6 +402,11 @@ int ip6_forward(struct sk_buff *skb) | |||
362 | return -ETIMEDOUT; | 402 | return -ETIMEDOUT; |
363 | } | 403 | } |
364 | 404 | ||
405 | if (pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) { | ||
406 | if (ip6_forward_proxy_check(skb)) | ||
407 | return ip6_input(skb); | ||
408 | } | ||
409 | |||
365 | if (!xfrm6_route_forward(skb)) { | 410 | if (!xfrm6_route_forward(skb)) { |
366 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 411 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); |
367 | goto drop; | 412 | goto drop; |