]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/ipv6/ndisc.c
netfilter: x_tables: pass xt_counters struct to counter allocator
[mirror_ubuntu-artful-kernel.git] / net / ipv6 / ndisc.c
index d8e671457d10539f751a28a0cc5cedb648ba0d83..7ebac630d3c603186be2fc0dcbaac7d7e74bfde6 100644 (file)
@@ -233,6 +233,7 @@ struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
                case ND_OPT_SOURCE_LL_ADDR:
                case ND_OPT_TARGET_LL_ADDR:
                case ND_OPT_MTU:
+               case ND_OPT_NONCE:
                case ND_OPT_REDIRECT_HDR:
                        if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
                                ND_PRINTK(2, warn,
@@ -568,7 +569,8 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 }
 
 void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
-                  const struct in6_addr *daddr, const struct in6_addr *saddr)
+                  const struct in6_addr *daddr, const struct in6_addr *saddr,
+                  u64 nonce)
 {
        struct sk_buff *skb;
        struct in6_addr addr_buf;
@@ -588,6 +590,8 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
        if (inc_opt)
                optlen += ndisc_opt_addr_space(dev,
                                               NDISC_NEIGHBOUR_SOLICITATION);
+       if (nonce != 0)
+               optlen += 8;
 
        skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
        if (!skb)
@@ -605,6 +609,13 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
                ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
                                       dev->dev_addr,
                                       NDISC_NEIGHBOUR_SOLICITATION);
+       if (nonce != 0) {
+               u8 *opt = skb_put(skb, 8);
+
+               opt[0] = ND_OPT_NONCE;
+               opt[1] = 8 >> 3;
+               memcpy(opt + 2, &nonce, 6);
+       }
 
        ndisc_send_skb(skb, daddr, saddr);
 }
@@ -693,12 +704,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
                                  "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
                                  __func__, target);
                }
-               ndisc_send_ns(dev, target, target, saddr);
+               ndisc_send_ns(dev, target, target, saddr, 0);
        } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
                neigh_app_ns(neigh);
        } else {
                addrconf_addr_solict_mult(target, &mcaddr);
-               ndisc_send_ns(dev, target, &mcaddr, saddr);
+               ndisc_send_ns(dev, target, &mcaddr, saddr, 0);
        }
 }
 
@@ -742,6 +753,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
        int dad = ipv6_addr_any(saddr);
        bool inc;
        int is_router = -1;
+       u64 nonce = 0;
 
        if (skb->len < sizeof(struct nd_msg)) {
                ND_PRINTK(2, warn, "NS: packet too short\n");
@@ -786,6 +798,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                        return;
                }
        }
+       if (ndopts.nd_opts_nonce)
+               memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6);
 
        inc = ipv6_addr_is_multicast(daddr);
 
@@ -794,6 +808,15 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 have_ifp:
                if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
                        if (dad) {
+                               if (nonce != 0 && ifp->dad_nonce == nonce) {
+                                       u8 *np = (u8 *)&nonce;
+                                       /* Matching nonce if looped back */
+                                       ND_PRINTK(2, notice,
+                                                 "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored\n",
+                                                 ifp->idev->dev->name,
+                                                 &ifp->addr, np);
+                                       goto out;
+                               }
                                /*
                                 * We are colliding with another node
                                 * who is doing DAD