]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv6/ndisc.c
[IPV6] ADDRCONF: Convert addrconf_lock to RCU.
[linux-2.6-omap-h63xx.git] / net / ipv6 / ndisc.c
index ed01f9a330d6d6eb2900ddcf44a08be81381ee0b..76517a5f65767b9925ba23710186bbd3306333ed 100644 (file)
@@ -736,8 +736,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev = NULL;
        struct neighbour *neigh;
+       struct pneigh_entry *pneigh = NULL;
        int dad = ipv6_addr_any(saddr);
        int inc;
+       int is_router;
 
        if (ipv6_addr_is_multicast(&msg->target)) {
                ND_PRINTK2(KERN_WARNING 
@@ -822,7 +824,9 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 
                if (ipv6_chk_acast_addr(dev, &msg->target) ||
                    (idev->cnf.forwarding && 
-                    pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
+                    (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
+                    (pneigh = pneigh_lookup(&nd_tbl,
+                                            &msg->target, dev, 0)) != NULL)) {
                        if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
                            skb->pkt_type != PACKET_HOST &&
                            inc != 0 &&
@@ -843,12 +847,17 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                        goto out;
        }
 
+       if (pneigh)
+               is_router = pneigh->flags & NTF_ROUTER;
+       else
+               is_router = idev->cnf.forwarding;
+
        if (dad) {
                struct in6_addr maddr;
 
                ipv6_addr_all_nodes(&maddr);
                ndisc_send_na(dev, NULL, &maddr, &msg->target,
-                             idev->cnf.forwarding, 0, (ifp != NULL), 1);
+                             is_router, 0, (ifp != NULL), 1);
                goto out;
        }
 
@@ -869,7 +878,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                             NEIGH_UPDATE_F_OVERRIDE);
        if (neigh || !dev->hard_header) {
                ndisc_send_na(dev, neigh, saddr, &msg->target,
-                             idev->cnf.forwarding, 
+                             is_router,
                              1, (ifp != NULL && inc), inc);
                if (neigh)
                        neigh_release(neigh);
@@ -952,6 +961,20 @@ static void ndisc_recv_na(struct sk_buff *skb)
                if (neigh->nud_state & NUD_FAILED)
                        goto out;
 
+               /*
+                * Don't update the neighbor cache entry on a proxy NA from
+                * ourselves because either the proxied node is off link or it
+                * has already sent a NA to us.
+                */
+               if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
+                   ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
+                   pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
+                       /* XXX: idev->cnf.prixy_ndp */
+                       WARN_ON(skb->dst != NULL &&
+                               ((struct rt6_info *)skb->dst)->rt6i_idev);
+                       goto out;
+               }
+
                neigh_update(neigh, lladdr,
                             msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
                             NEIGH_UPDATE_F_WEAK_OVERRIDE|