summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2015-11-04 01:00:42 +0000
committerhrs <hrs@FreeBSD.org>2015-11-04 01:00:42 +0000
commit3fe8aea7a4cf3b7bac37386c8601bc1fcb38e431 (patch)
tree2f357707fa2e57c41af2b7bc658281b1e52bbe95 /sys/netinet6
parent6e153191224677d8b773d7d47d9a0a076e58856b (diff)
downloadFreeBSD-src-3fe8aea7a4cf3b7bac37386c8601bc1fcb38e431.zip
FreeBSD-src-3fe8aea7a4cf3b7bac37386c8601bc1fcb38e431.tar.gz
MFC r288600:
- 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.
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/nd6.c26
-rw-r--r--sys/netinet6/nd6_nbr.c40
2 files changed, 47 insertions, 19 deletions
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index d2aa188..8032e9f 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -687,8 +687,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.
*/
@@ -1341,7 +1364,8 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
/* 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) {
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 8f287dc..5232f8f 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -86,11 +86,11 @@ static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *);
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 *,
@@ -1242,9 +1242,11 @@ nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n)
}
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);
}
@@ -1283,6 +1285,7 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
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.
@@ -1319,8 +1322,10 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
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;
}
@@ -1353,13 +1358,12 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
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);
}
/*
@@ -1429,7 +1433,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;
}
@@ -1439,9 +1444,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 {
/*
@@ -1469,11 +1473,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 {
/*
@@ -1562,10 +1566,10 @@ nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp)
}
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++;
OpenPOWER on IntegriCloud