diff options
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-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, if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) IP6_ECN_set_ce(inner_iph); } +static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) +{ + struct ip6_tnl_parm *p = &t->parms; + int ret = 0; + + if (p->flags & IP6_TNL_F_CAP_RCV) { + struct net_device *ldev = NULL; + + if (p->link) + ldev = dev_get_by_index(p->link); + + if ((ipv6_addr_is_multicast(&p->laddr) || + likely(ipv6_chk_addr(&p->laddr, ldev, 0))) && + likely(!ipv6_chk_addr(&p->raddr, NULL, 0))) + ret = 1; + + if (ldev) + dev_put(ldev); + } + return ret; +} /** * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally @@ -518,7 +539,7 @@ ip6ip6_rcv(struct sk_buff *skb) goto discard; } - if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { + if (!ip6_tnl_rcv_ctl(t)) { t->stat.rx_dropped++; read_unlock(&ip6ip6_lock); goto discard; @@ -597,6 +618,34 @@ ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr) return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); } +static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) +{ + struct ip6_tnl_parm *p = &t->parms; + int ret = 0; + + if (p->flags & IP6_TNL_F_CAP_XMIT) { + struct net_device *ldev = NULL; + + if (p->link) + ldev = dev_get_by_index(p->link); + + if (unlikely(!ipv6_chk_addr(&p->laddr, ldev, 0))) + printk(KERN_WARNING + "%s xmit: Local address not yet configured!\n", + p->name); + else if (!ipv6_addr_is_multicast(&p->raddr) && + unlikely(ipv6_chk_addr(&p->raddr, NULL, 0))) + printk(KERN_WARNING + "%s xmit: Routing loop! " + "Remote address found on this node!\n", + p->name); + else + ret = 1; + if (ldev) + dev_put(ldev); + } + return ret; +} /** * ip6ip6_tnl_xmit - encapsulate packet and send * @skb: the outgoing socket buffer @@ -634,10 +683,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_err; } if (skb->protocol != htons(ETH_P_IPV6) || - !(t->parms.flags & IP6_TNL_F_CAP_XMIT) || - ip6ip6_tnl_addr_conflict(t, ipv6h)) { + !ip6_tnl_xmit_ctl(t) || ip6ip6_tnl_addr_conflict(t, ipv6h)) goto tx_err; - } + if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) { struct ipv6_tlv_tnl_enc_lim *tel; tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset]; @@ -768,39 +816,19 @@ tx_err: static void ip6_tnl_set_cap(struct ip6_tnl *t) { struct ip6_tnl_parm *p = &t->parms; - struct in6_addr *laddr = &p->laddr; - struct in6_addr *raddr = &p->raddr; - int ltype = ipv6_addr_type(laddr); - int rtype = ipv6_addr_type(raddr); + int ltype = ipv6_addr_type(&p->laddr); + int rtype = ipv6_addr_type(&p->raddr); p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV); - if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY && - ((ltype|rtype) & - (IPV6_ADDR_UNICAST| - IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL| - IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) { - struct net_device *ldev = NULL; - int l_ok = 1; - int r_ok = 1; - - if (p->link) - ldev = dev_get_by_index(p->link); - - if (ltype&IPV6_ADDR_UNICAST && !ipv6_chk_addr(laddr, ldev, 0)) - l_ok = 0; - - if (rtype&IPV6_ADDR_UNICAST && ipv6_chk_addr(raddr, NULL, 0)) - r_ok = 0; - - if (l_ok && r_ok) { - if (ltype&IPV6_ADDR_UNICAST) - p->flags |= IP6_TNL_F_CAP_XMIT; - if (rtype&IPV6_ADDR_UNICAST) - p->flags |= IP6_TNL_F_CAP_RCV; - } - if (ldev) - dev_put(ldev); + if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) && + rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) && + !((ltype|rtype) & IPV6_ADDR_LOOPBACK) && + !((ltype|rtype) & IPV6_ADDR_LINKLOCAL)) { + if (ltype&IPV6_ADDR_UNICAST) + p->flags |= IP6_TNL_F_CAP_XMIT; + if (rtype&IPV6_ADDR_UNICAST) + p->flags |= IP6_TNL_F_CAP_RCV; } } |