Author: hrs
Date: Sat Oct  3 12:09:12 2015
New Revision: 288600
URL: https://svnweb.freebsd.org/changeset/base/288600

Log:
  - Schedule DAD for IN6_IFF_TENTATIVE addresses in nd6_timer().  This
    catches cases that DAD probes cannot be sent because of
    IFF_UP && !IFF_DRV_RUNNING.
  
  - nd6_dad_starttimer() now calls nd6_dad_ns_output(), instead of
    calling it before nd6_dad_starttimer().
  
  - Do not release an entry in dadq when a duplicate entry is being
    added.

Modified:
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6_nbr.c

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c     Sat Oct  3 11:43:54 2015        (r288599)
+++ head/sys/netinet6/nd6.c     Sat Oct  3 12:09:12 2015        (r288600)
@@ -810,8 +810,31 @@ nd6_timer(void *arg)
                                        goto addrloop;
                                }
                        }
+               } else if ((ia6->ia6_flags & IN6_IFF_TENTATIVE) != 0) {
+                       /*
+                        * Schedule DAD for a tentative address.  This happens
+                        * if the interface was down or not running
+                        * when the address was configured.
+                        */
+                       int delay;
+
+                       delay = arc4random() %
+                           (MAX_RTR_SOLICITATION_DELAY * hz);
+                       nd6_dad_start((struct ifaddr *)ia6, delay);
                } else {
                        /*
+                        * Check status of the interface.  If it is down,
+                        * mark the address as tentative for future DAD.
+                        */
+                       if ((ia6->ia_ifp->if_flags & IFF_UP) == 0 ||
+                           (ia6->ia_ifp->if_drv_flags & IFF_DRV_RUNNING)
+                               == 0 ||
+                           (ND_IFINFO(ia6->ia_ifp)->flags &
+                               ND6_IFF_IFDISABLED) != 0) {
+                               ia6->ia6_flags &= ~IN6_IFF_DUPLICATED;
+                               ia6->ia6_flags |= IN6_IFF_TENTATIVE;
+                       }
+                       /*
                         * A new RA might have made a deprecated address
                         * preferred.
                         */
@@ -1452,7 +1475,8 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
                        /* Mark all IPv6 address as tentative. */
 
                        ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
-                       if ((ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) {
+                       if (V_ip6_dad_count > 0 &&
+                           (ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) {
                                IF_ADDR_RLOCK(ifp);
                                TAILQ_FOREACH(ifa, &ifp->if_addrhead,
                                    ifa_link) {

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c Sat Oct  3 11:43:54 2015        (r288599)
+++ head/sys/netinet6/nd6_nbr.c Sat Oct  3 12:09:12 2015        (r288600)
@@ -85,11 +85,11 @@ static struct dadq *nd6_dad_find(struct 
 static void nd6_dad_add(struct dadq *dp);
 static void nd6_dad_del(struct dadq *dp);
 static void nd6_dad_rele(struct dadq *);
-static void nd6_dad_starttimer(struct dadq *, int);
+static void nd6_dad_starttimer(struct dadq *, int, int);
 static void nd6_dad_stoptimer(struct dadq *);
 static void nd6_dad_timer(struct dadq *);
 static void nd6_dad_duplicated(struct ifaddr *, struct dadq *);
-static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
+static void nd6_dad_ns_output(struct dadq *);
 static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *);
 static void nd6_dad_na_input(struct ifaddr *);
 static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
@@ -1199,9 +1199,11 @@ nd6_dad_find(struct ifaddr *ifa, struct 
 }
 
 static void
-nd6_dad_starttimer(struct dadq *dp, int ticks)
+nd6_dad_starttimer(struct dadq *dp, int ticks, int send_ns)
 {
 
+       if (send_ns != 0)
+               nd6_dad_ns_output(dp);
        callout_reset(&dp->dad_timer_ch, ticks,
            (void (*)(void *))nd6_dad_timer, (void *)dp);
 }
@@ -1240,6 +1242,7 @@ nd6_dad_start(struct ifaddr *ifa, int de
        struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
        struct dadq *dp;
        char ip6buf[INET6_ADDRSTRLEN];
+       int send_ns;
 
        /*
         * If we don't need DAD, don't do it.
@@ -1276,8 +1279,10 @@ nd6_dad_start(struct ifaddr *ifa, int de
                return;
        }
        if ((dp = nd6_dad_find(ifa, NULL)) != NULL) {
-               /* DAD already in progress */
-               nd6_dad_rele(dp);
+               /*
+                * DAD already in progress.  Let the existing entry
+                * to finish it.
+                */
                return;
        }
 
@@ -1310,13 +1315,12 @@ nd6_dad_start(struct ifaddr *ifa, int de
        dp->dad_ns_lcount = dp->dad_loopbackprobe = 0;
        refcount_init(&dp->dad_refcnt, 1);
        nd6_dad_add(dp);
+       send_ns = 0;
        if (delay == 0) {
-               nd6_dad_ns_output(dp, ifa);
-               nd6_dad_starttimer(dp,
-                   (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
-       } else {
-               nd6_dad_starttimer(dp, delay);
+               send_ns = 1;
+               delay = (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000;
        }
+       nd6_dad_starttimer(dp, delay, send_ns);
 }
 
 /*
@@ -1386,7 +1390,8 @@ nd6_dad_timer(struct dadq *dp)
        if ((dp->dad_ns_tcount > V_dad_maxtry) &&
            (((ifp->if_flags & IFF_UP) == 0) ||
             ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0))) {
-               nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
+               nd6log((LOG_INFO, "%s: could not run DAD "
+                   "because the interface was down or not running.\n",
                    if_name(ifa->ifa_ifp)));
                goto err;
        }
@@ -1396,9 +1401,8 @@ nd6_dad_timer(struct dadq *dp)
                /*
                 * We have more NS to go.  Send NS packet for DAD.
                 */
-               nd6_dad_ns_output(dp, ifa);
                nd6_dad_starttimer(dp,
-                   (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+                   (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000, 1);
                goto done;
        } else {
                /*
@@ -1426,11 +1430,11 @@ nd6_dad_timer(struct dadq *dp)
                         * Send an NS immediately and increase dad_count by
                         * V_nd6_mmaxtries - 1.
                         */
-                       nd6_dad_ns_output(dp, ifa);
                        dp->dad_count =
                            dp->dad_ns_ocount + V_nd6_mmaxtries - 1;
                        nd6_dad_starttimer(dp,
-                           (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+                           (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000,
+                           1);
                        goto done;
                } else {
                        /*
@@ -1517,10 +1521,10 @@ nd6_dad_duplicated(struct ifaddr *ifa, s
 }
 
 static void
-nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
+nd6_dad_ns_output(struct dadq *dp)
 {
-       struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
-       struct ifnet *ifp = ifa->ifa_ifp;
+       struct in6_ifaddr *ia = (struct in6_ifaddr *)dp->dad_ifa;
+       struct ifnet *ifp = dp->dad_ifa->ifa_ifp;
        int i;
 
        dp->dad_ns_tcount++;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to