Index: sys/netinet6/nd6_nbr.c =================================================================== --- sys/netinet6/nd6_nbr.c +++ sys/netinet6/nd6_nbr.c @@ -87,7 +87,7 @@ 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, int); +static void nd6_dad_starttimer(struct dadq *, int); static void nd6_dad_stoptimer(struct dadq *); static void nd6_dad_timer(struct dadq *); static void nd6_dad_duplicated(struct ifaddr *, struct dadq *); @@ -1125,19 +1125,22 @@ #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) { - DADQ_WLOCK(); + DADQ_WLOCK_ASSERT(); + TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list); dp->dad_ondadq = true; - DADQ_WUNLOCK(); } static void @@ -1188,13 +1191,13 @@ } static void -nd6_dad_starttimer(struct dadq *dp, int ticks, int send_ns) +nd6_dad_starttimer(struct dadq *dp, int ticks) { - if (send_ns != 0) - nd6_dad_ns_output(dp); + DADQ_WLOCK_ASSERT(); + callout_reset(&dp->dad_timer_ch, ticks, - (void (*)(void *))nd6_dad_timer, (void *)dp); + (void (*)(void *))nd6_dad_timer, dp); } static void @@ -1209,6 +1212,7 @@ { if (refcount_release(&dp->dad_refcnt)) { + KASSERT(!dp->dad_ondadq, ("dp %p still on DAD queue", dp)); ifa_free(dp->dad_ifa); free(dp, M_IP6NDP); } @@ -1269,7 +1273,8 @@ 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, + CALLOUT_RETURNUNLOCKED); #ifdef VIMAGE dp->dad_vnet = curvnet; #endif @@ -1291,8 +1296,10 @@ /* Add this to the dadq and add a reference for the dadq. */ refcount_init(&dp->dad_refcnt, 1); + DADQ_WLOCK(); nd6_dad_add(dp); - nd6_dad_starttimer(dp, delay, 0); + nd6_dad_starttimer(dp, delay); + DADQ_WUNLOCK(); } /* @@ -1325,6 +1332,7 @@ struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; char ip6buf[INET6_ADDRSTRLEN]; + DADQ_WLOCK_ASSERT(); KASSERT(ia != NULL, ("DAD entry %p with no address", dp)); if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { @@ -1364,7 +1372,9 @@ * We have more NS to go. Send NS packet for DAD. */ nd6_dad_starttimer(dp, - (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000, 1); + (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); + nd6_dad_ns_output(dp); + /* DAD queue has been unlocked. */ goto done; } else { /* @@ -1395,8 +1405,9 @@ dp->dad_count = dp->dad_ns_ocount + V_nd6_mmaxtries - 1; nd6_dad_starttimer(dp, - (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000, - 1); + (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); + nd6_dad_ns_output(dp); + /* DAD queue has been unlocked. */ goto done; } else { /* @@ -1421,7 +1432,9 @@ } } err: - nd6_dad_del(dp); + TAILQ_REMOVE(&V_dadq, dp, dad_list); + nd6_dad_rele(dp); + DADQ_WUNLOCK(); done: CURVNET_RESTORE(); } @@ -1487,11 +1500,15 @@ struct ifnet *ifp = dp->dad_ifa->ifa_ifp; int i; + DADQ_WLOCK_ASSERT(); + dp->dad_ns_tcount++; if ((ifp->if_flags & IFF_UP) == 0) { + DADQ_WUNLOCK(); return; } if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + DADQ_WUNLOCK(); return; } @@ -1508,6 +1525,7 @@ * should work well in almost all cases. */ } + DADQ_WUNLOCK(); nd6_ns_output(ifp, NULL, NULL, &ia->ia_addr.sin6_addr, (uint8_t *)&dp->dad_nonce[0]); }