diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 96 |
1 files changed, 62 insertions, 34 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index fdf1a2fa3a3d..22debbf28b8a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -494,6 +494,27 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, | |||
494 | if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) | 494 | if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) |
495 | IP6_ECN_set_ce(inner_iph); | 495 | IP6_ECN_set_ce(inner_iph); |
496 | } | 496 | } |
497 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | ||
498 | { | ||
499 | struct ip6_tnl_parm *p = &t->parms; | ||
500 | int ret = 0; | ||
501 | |||
502 | if (p->flags & IP6_TNL_F_CAP_RCV) { | ||
503 | struct net_device *ldev = NULL; | ||
504 | |||
505 | if (p->link) | ||
506 | ldev = dev_get_by_index(p->link); | ||
507 | |||
508 | if ((ipv6_addr_is_multicast(&p->laddr) || | ||
509 | likely(ipv6_chk_addr(&p->laddr, ldev, 0))) && | ||
510 | likely(!ipv6_chk_addr(&p->raddr, NULL, 0))) | ||
511 | ret = 1; | ||
512 | |||
513 | if (ldev) | ||
514 | dev_put(ldev); | ||
515 | } | ||
516 | return ret; | ||
517 | } | ||
497 | 518 | ||
498 | /** | 519 | /** |
499 | * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally | 520 | * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally |
@@ -518,7 +539,7 @@ ip6ip6_rcv(struct sk_buff *skb) | |||
518 | goto discard; | 539 | goto discard; |
519 | } | 540 | } |
520 | 541 | ||
521 | if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { | 542 | if (!ip6_tnl_rcv_ctl(t)) { |
522 | t->stat.rx_dropped++; | 543 | t->stat.rx_dropped++; |
523 | read_unlock(&ip6ip6_lock); | 544 | read_unlock(&ip6ip6_lock); |
524 | goto discard; | 545 | goto discard; |
@@ -597,6 +618,34 @@ ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr) | |||
597 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | 618 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); |
598 | } | 619 | } |
599 | 620 | ||
621 | static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | ||
622 | { | ||
623 | struct ip6_tnl_parm *p = &t->parms; | ||
624 | int ret = 0; | ||
625 | |||
626 | if (p->flags & IP6_TNL_F_CAP_XMIT) { | ||
627 | struct net_device *ldev = NULL; | ||
628 | |||
629 | if (p->link) | ||
630 | ldev = dev_get_by_index(p->link); | ||
631 | |||
632 | if (unlikely(!ipv6_chk_addr(&p->laddr, ldev, 0))) | ||
633 | printk(KERN_WARNING | ||
634 | "%s xmit: Local address not yet configured!\n", | ||
635 | p->name); | ||
636 | else if (!ipv6_addr_is_multicast(&p->raddr) && | ||
637 | unlikely(ipv6_chk_addr(&p->raddr, NULL, 0))) | ||
638 | printk(KERN_WARNING | ||
639 | "%s xmit: Routing loop! " | ||
640 | "Remote address found on this node!\n", | ||
641 | p->name); | ||
642 | else | ||
643 | ret = 1; | ||
644 | if (ldev) | ||
645 | dev_put(ldev); | ||
646 | } | ||
647 | return ret; | ||
648 | } | ||
600 | /** | 649 | /** |
601 | * ip6ip6_tnl_xmit - encapsulate packet and send | 650 | * ip6ip6_tnl_xmit - encapsulate packet and send |
602 | * @skb: the outgoing socket buffer | 651 | * @skb: the outgoing socket buffer |
@@ -634,10 +683,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
634 | goto tx_err; | 683 | goto tx_err; |
635 | } | 684 | } |
636 | if (skb->protocol != htons(ETH_P_IPV6) || | 685 | if (skb->protocol != htons(ETH_P_IPV6) || |
637 | !(t->parms.flags & IP6_TNL_F_CAP_XMIT) || | 686 | !ip6_tnl_xmit_ctl(t) || ip6ip6_tnl_addr_conflict(t, ipv6h)) |
638 | ip6ip6_tnl_addr_conflict(t, ipv6h)) { | ||
639 | goto tx_err; | 687 | goto tx_err; |
640 | } | 688 | |
641 | if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) { | 689 | if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) { |
642 | struct ipv6_tlv_tnl_enc_lim *tel; | 690 | struct ipv6_tlv_tnl_enc_lim *tel; |
643 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset]; | 691 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset]; |
@@ -768,39 +816,19 @@ tx_err: | |||
768 | static void ip6_tnl_set_cap(struct ip6_tnl *t) | 816 | static void ip6_tnl_set_cap(struct ip6_tnl *t) |
769 | { | 817 | { |
770 | struct ip6_tnl_parm *p = &t->parms; | 818 | struct ip6_tnl_parm *p = &t->parms; |
771 | struct in6_addr *laddr = &p->laddr; | 819 | int ltype = ipv6_addr_type(&p->laddr); |
772 | struct in6_addr *raddr = &p->raddr; | 820 | int rtype = ipv6_addr_type(&p->raddr); |
773 | int ltype = ipv6_addr_type(laddr); | ||
774 | int rtype = ipv6_addr_type(raddr); | ||
775 | 821 | ||
776 | p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV); | 822 | p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV); |
777 | 823 | ||
778 | if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY && | 824 | if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) && |
779 | ((ltype|rtype) & | 825 | rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) && |
780 | (IPV6_ADDR_UNICAST| | 826 | !((ltype|rtype) & IPV6_ADDR_LOOPBACK) && |
781 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL| | 827 | !((ltype|rtype) & IPV6_ADDR_LINKLOCAL)) { |
782 | IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) { | 828 | if (ltype&IPV6_ADDR_UNICAST) |
783 | struct net_device *ldev = NULL; | 829 | p->flags |= IP6_TNL_F_CAP_XMIT; |
784 | int l_ok = 1; | 830 | if (rtype&IPV6_ADDR_UNICAST) |
785 | int r_ok = 1; | 831 | p->flags |= IP6_TNL_F_CAP_RCV; |
786 | |||
787 | if (p->link) | ||
788 | ldev = dev_get_by_index(p->link); | ||
789 | |||
790 | if (ltype&IPV6_ADDR_UNICAST && !ipv6_chk_addr(laddr, ldev, 0)) | ||
791 | l_ok = 0; | ||
792 | |||
793 | if (rtype&IPV6_ADDR_UNICAST && ipv6_chk_addr(raddr, NULL, 0)) | ||
794 | r_ok = 0; | ||
795 | |||
796 | if (l_ok && r_ok) { | ||
797 | if (ltype&IPV6_ADDR_UNICAST) | ||
798 | p->flags |= IP6_TNL_F_CAP_XMIT; | ||
799 | if (rtype&IPV6_ADDR_UNICAST) | ||
800 | p->flags |= IP6_TNL_F_CAP_RCV; | ||
801 | } | ||
802 | if (ldev) | ||
803 | dev_put(ldev); | ||
804 | } | 832 | } |
805 | } | 833 | } |
806 | 834 | ||