diff options
author | Jonathan T. Looney <jtl@FreeBSD.org> | 2018-03-24 13:18:09 +0000 |
---|---|---|
committer | Jonathan T. Looney <jtl@FreeBSD.org> | 2018-03-24 13:18:09 +0000 |
commit | 20cb3e25570f078721b0c62f4bc669f245c36dbe (patch) | |
tree | da14cc449ba5d8eff054df91574abdce72c02810 /sys | |
parent | 161bf65f8a3db9f8e8bc4f7afde54f32f2d95a23 (diff) | |
download | src-20cb3e25570f078721b0c62f4bc669f245c36dbe.tar.gz src-20cb3e25570f078721b0c62f4bc669f245c36dbe.zip |
This change adds a flag to the DAD entry to indicate whether it is
currently on the queue. This prevents accidentally doubly-removing a DAD
entry from the queue, while also simplifying some of the logic in
nd6_dad_stop().
Reviewed by: ae, hrs, vangyzen
MFC after: 2 weeks
Sponsored by: Netflix, Inc.
Differential Revision: https://reviews.freebsd.org/D10943
Notes
Notes:
svn path=/head/; revision=331488
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet6/nd6_nbr.c | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 786f6bdbfd54..50d417bbc08b 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1120,6 +1120,7 @@ struct dadq { #define ND_OPT_NONCE_LEN32 \ ((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t)) uint32_t dad_nonce[ND_OPT_NONCE_LEN32]; + bool dad_ondadq; /* on dadq? Protected by DADQ_WLOCK. */ }; static VNET_DEFINE(TAILQ_HEAD(, dadq), dadq); @@ -1138,6 +1139,7 @@ nd6_dad_add(struct dadq *dp) DADQ_WLOCK(); TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list); + dp->dad_ondadq = true; DADQ_WUNLOCK(); } @@ -1146,9 +1148,17 @@ nd6_dad_del(struct dadq *dp) { DADQ_WLOCK(); - TAILQ_REMOVE(&V_dadq, dp, dad_list); - DADQ_WUNLOCK(); - nd6_dad_rele(dp); + if (dp->dad_ondadq) { + /* + * Remove dp from the dadq and release the dadq's + * reference. + */ + TAILQ_REMOVE(&V_dadq, dp, dad_list); + dp->dad_ondadq = false; + DADQ_WUNLOCK(); + nd6_dad_rele(dp); + } else + DADQ_WUNLOCK(); } static struct dadq * @@ -1281,6 +1291,8 @@ nd6_dad_start(struct ifaddr *ifa, int delay) dp->dad_ns_icount = dp->dad_na_icount = 0; dp->dad_ns_ocount = dp->dad_ns_tcount = 0; dp->dad_ns_lcount = dp->dad_loopbackprobe = 0; + + /* Add this to the dadq and add a reference for the dadq. */ refcount_init(&dp->dad_refcnt, 1); nd6_dad_add(dp); nd6_dad_starttimer(dp, delay, 0); @@ -1301,17 +1313,9 @@ nd6_dad_stop(struct ifaddr *ifa) } nd6_dad_stoptimer(dp); - - /* - * The DAD queue entry may have been removed by nd6_dad_timer() while - * we were waiting for it to stop, so re-do the lookup. - */ - nd6_dad_rele(dp); - dp = nd6_dad_find(ifa, NULL); - if (dp == NULL) - return; - nd6_dad_del(dp); + + /* Release this function's reference, acquired by nd6_dad_find(). */ nd6_dad_rele(dp); } |