aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c106
1 files changed, 92 insertions, 14 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4fb47a252913..66716911962e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -308,6 +308,56 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
308 return 0; 308 return 0;
309} 309}
310 310
311static 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 /*
349 * The proxying router can't forward traffic sent to a link-local
350 * address, so signal the sender and discard the packet. This
351 * behavior is clarified by the MIPv6 specification.
352 */
353 if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) {
354 dst_link_failure(skb);
355 return -1;
356 }
357
358 return 0;
359}
360
311static inline int ip6_forward_finish(struct sk_buff *skb) 361static inline int ip6_forward_finish(struct sk_buff *skb)
312{ 362{
313 return dst_output(skb); 363 return dst_output(skb);
@@ -362,6 +412,18 @@ int ip6_forward(struct sk_buff *skb)
362 return -ETIMEDOUT; 412 return -ETIMEDOUT;
363 } 413 }
364 414
415 /* XXX: idev->cnf.proxy_ndp? */
416 if (ipv6_devconf.proxy_ndp &&
417 pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
418 int proxied = ip6_forward_proxy_check(skb);
419 if (proxied > 0)
420 return ip6_input(skb);
421 else if (proxied < 0) {
422 IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
423 goto drop;
424 }
425 }
426
365 if (!xfrm6_route_forward(skb)) { 427 if (!xfrm6_route_forward(skb)) {
366 IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); 428 IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
367 goto drop; 429 goto drop;
@@ -475,17 +537,25 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
475 switch (**nexthdr) { 537 switch (**nexthdr) {
476 538
477 case NEXTHDR_HOP: 539 case NEXTHDR_HOP:
540 break;
478 case NEXTHDR_ROUTING: 541 case NEXTHDR_ROUTING:
542 found_rhdr = 1;
543 break;
479 case NEXTHDR_DEST: 544 case NEXTHDR_DEST:
480 if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1; 545#ifdef CONFIG_IPV6_MIP6
481 if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset; 546 if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
482 offset += ipv6_optlen(exthdr); 547 break;
483 *nexthdr = &exthdr->nexthdr; 548#endif
484 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); 549 if (found_rhdr)
550 return offset;
485 break; 551 break;
486 default : 552 default :
487 return offset; 553 return offset;
488 } 554 }
555
556 offset += ipv6_optlen(exthdr);
557 *nexthdr = &exthdr->nexthdr;
558 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
489 } 559 }
490 560
491 return offset; 561 return offset;
@@ -726,6 +796,14 @@ fail:
726 return err; 796 return err;
727} 797}
728 798
799static inline int ip6_rt_check(struct rt6key *rt_key,
800 struct in6_addr *fl_addr,
801 struct in6_addr *addr_cache)
802{
803 return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) &&
804 (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)));
805}
806
729static struct dst_entry *ip6_sk_dst_check(struct sock *sk, 807static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
730 struct dst_entry *dst, 808 struct dst_entry *dst,
731 struct flowi *fl) 809 struct flowi *fl)
@@ -741,8 +819,8 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
741 * that we do not support routing by source, TOS, 819 * that we do not support routing by source, TOS,
742 * and MSG_DONTROUTE --ANK (980726) 820 * and MSG_DONTROUTE --ANK (980726)
743 * 821 *
744 * 1. If route was host route, check that 822 * 1. ip6_rt_check(): If route was host route,
745 * cached destination is current. 823 * check that cached destination is current.
746 * If it is network route, we still may 824 * If it is network route, we still may
747 * check its validity using saved pointer 825 * check its validity using saved pointer
748 * to the last used address: daddr_cache. 826 * to the last used address: daddr_cache.
@@ -753,11 +831,11 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
753 * sockets. 831 * sockets.
754 * 2. oif also should be the same. 832 * 2. oif also should be the same.
755 */ 833 */
756 if (((rt->rt6i_dst.plen != 128 || 834 if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) ||
757 !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) 835#ifdef CONFIG_IPV6_SUBTREES
758 && (np->daddr_cache == NULL || 836 ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) ||
759 !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) 837#endif
760 || (fl->oif && fl->oif != dst->dev->ifindex)) { 838 (fl->oif && fl->oif != dst->dev->ifindex)) {
761 dst_release(dst); 839 dst_release(dst);
762 dst = NULL; 840 dst = NULL;
763 } 841 }
@@ -866,7 +944,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
866 /* initialize protocol header pointer */ 944 /* initialize protocol header pointer */
867 skb->h.raw = skb->data + fragheaderlen; 945 skb->h.raw = skb->data + fragheaderlen;
868 946
869 skb->ip_summed = CHECKSUM_HW; 947 skb->ip_summed = CHECKSUM_PARTIAL;
870 skb->csum = 0; 948 skb->csum = 0;
871 sk->sk_sndmsg_off = 0; 949 sk->sk_sndmsg_off = 0;
872 } 950 }
@@ -963,7 +1041,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
963 1041
964 hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); 1042 hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
965 1043
966 fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0); 1044 fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0);
967 maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); 1045 maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
968 1046
969 if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { 1047 if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {