Index: sys/netinet6/nd6_nbr.c =================================================================== --- sys/netinet6/nd6_nbr.c +++ sys/netinet6/nd6_nbr.c @@ -1196,10 +1196,13 @@ #define V_dadq VNET(dadq) #define V_dad_rwlock VNET(dad_rwlock) -#define DADQ_RLOCK() rw_rlock(&V_dad_rwlock) -#define DADQ_RUNLOCK() rw_runlock(&V_dad_rwlock) -#define DADQ_WLOCK() rw_wlock(&V_dad_rwlock) -#define DADQ_WUNLOCK() rw_wunlock(&V_dad_rwlock) +#define DADQ_RLOCK() rw_rlock(&V_dad_rwlock) +#define DADQ_RUNLOCK() rw_runlock(&V_dad_rwlock) +#define DADQ_WLOCK() rw_wlock(&V_dad_rwlock) +#define DADQ_WUNLOCK() rw_wunlock(&V_dad_rwlock) +#define DADQ_RLOCK_ASSERT() rw_assert(&V_dad_rwlock, RA_RLOCKED) +#define DADQ_WLOCK_ASSERT() rw_assert(&V_dad_rwlock, RA_WLOCKED) +#define DADQ_LOCK_ASSERT() rw_assert(&V_dad_rwlock, RA_LOCKED) static void nd6_dad_add(struct dadq *dp) @@ -1253,6 +1256,7 @@ nd6_dad_starttimer(struct dadq *dp, int ticks) { + DADQ_WLOCK_ASSERT(); callout_reset(&dp->dad_timer_ch, ticks, (void (*)(void *))nd6_dad_timer, (void *)dp); } @@ -1261,6 +1265,7 @@ nd6_dad_stoptimer(struct dadq *dp) { + DADQ_WLOCK_ASSERT(); callout_drain(&dp->dad_timer_ch); } @@ -1335,7 +1340,7 @@ ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); return; } - callout_init(&dp->dad_timer_ch, 0); + callout_init_rw(&dp->dad_timer_ch, &V_dad_rwlock, 0); #ifdef VIMAGE dp->dad_vnet = curvnet; #endif @@ -1358,11 +1363,11 @@ nd6_dad_add(dp); 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); + delay = (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000; } + DADQ_WLOCK(); + nd6_dad_starttimer(dp, delay); + DADQ_WUNLOCK(); } /* @@ -1379,7 +1384,9 @@ return; } + DADQ_WLOCK(); nd6_dad_stoptimer(dp); + DADQ_WUNLOCK(); /* * The DAD queue entry may have been removed by nd6_dad_timer() while @@ -1512,7 +1519,9 @@ } } err: - nd6_dad_del(dp); + /* We hold the DAD lock here. */ + TAILQ_REMOVE(&V_dadq, dp, dad_list); + nd6_dad_rele(dp); done: CURVNET_RESTORE(); }