On Tue, 27 Jan 2004, Andreas Jellinghaus wrote: > Hi Ville, > > it's the first ipv6_check_addr that results in "0". > if I understand that code right, it could be because > it matches only link and local addresses, but not global? No, ipv6_chk_addr() checks if any unicast address is configured to the host. For host and link-local scope addresses it also checks that the address is on the specified net_device, since the addresses aren't globally unique. The thing that probalby causes your tests to fail is that the local address is still tentative when you configure the tunnel. At the moment you need to wait until Duplicate Address Detection has completed for the local address (takes one second) before configuring your tunnel. Come to think of it, this behavior is unnecessarily restrictive. It's better to check the addresses when actually tunneling traffic, than at configuration time. Here is a new patch (against 2.6.2-rc2) which does just that. Would you test if it works for you? Regards, Ville ===== net/ipv6/ip6_tunnel.c 1.16 vs edited ===== --- 1.16/net/ipv6/ip6_tunnel.c Thu Jan 22 08:38:40 2004 +++ edited/net/ipv6/ip6_tunnel.c Tue Jan 27 10:12:33 2004 @@ -428,12 +428,10 @@ } break; case ICMPV6_PARAMPROB: - /* ignore if parameter problem not caused by a tunnel - encapsulation limit sub-option */ - if (code != ICMPV6_HDR_FIELD) { - break; - } - teli = parse_tlv_tnl_enc_lim(skb, skb->data); + if (code == ICMPV6_HDR_FIELD) + teli = parse_tlv_tnl_enc_lim(skb, skb->data); + else + teli = 0; if (teli && teli == ntohl(info) - 2) { tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; @@ -445,6 +443,10 @@ "tunnel!\n", t->parms.name); rel_msg = 1; } + } else if (net_ratelimit()) { + printk(KERN_WARNING + "%s: Recipient unable to parse tunneled " + "packet!\n ", t->parms.name); } break; case ICMPV6_PKT_TOOBIG: @@ -489,6 +491,30 @@ read_unlock(&ip6ip6_lock); } +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 in6_addr *laddr = &p->laddr; + struct in6_addr *raddr = &p->raddr; + struct net_device *ldev = NULL; + + if (p->link) + ldev = dev_get_by_index(p->link); + + if ((ipv6_addr_type(laddr)&IPV6_ADDR_MULTICAST || + likely(ipv6_chk_addr(laddr, ldev, 0))) && + likely(!ipv6_chk_addr(raddr, NULL, 0))) + ret = 1; + + if (ldev) + dev_put(ldev); + } + return ret; +} + /** * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally * @skb: received socket buffer @@ -510,7 +536,7 @@ read_lock(&ip6ip6_lock); if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { - 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; @@ -585,6 +611,37 @@ return !ipv6_addr_cmp(&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 in6_addr *laddr = &p->laddr; + struct in6_addr *raddr = &p->raddr; + struct net_device *ldev = NULL; + + if (p->link) + ldev = dev_get_by_index(p->link); + + if (unlikely(!ipv6_chk_addr(laddr, ldev, 0))) + printk(KERN_WARNING + "%s xmit: Local address not yet configured!\n", + p->name); + else if (!(ipv6_addr_type(raddr)&IPV6_ADDR_MULTICAST) && + unlikely(ipv6_chk_addr(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 @@ -620,8 +677,7 @@ 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) { @@ -765,32 +821,14 @@ 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) || p->link)) { + if (ltype&IPV6_ADDR_UNICAST) + p->flags |= IP6_TNL_F_CAP_XMIT; + if (rtype&IPV6_ADDR_UNICAST) + p->flags |= IP6_TNL_F_CAP_RCV; } } -- Ville Nuorvala Research Assistant, Institute of Digital Communications, Helsinki University of Technology email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257 - : send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html