Addresses with pending DAD live in a global queue. In this case, a
callout is associated with each entry. The callout transmits neighbour
solicitations until the system decides the address is no longer
tentative, or until a duplicate address is discovered. At this point
the entry is dequeued and freed. DAD may be manually stopped as well.
The callout currently runs with Giant held, which is not really nice
since it transmits packets. Reorganize DAD queue locking to interlock
properly with the callout:
- Configure the callout to acquire the DAD queue lock before running. The lock is dropped before transmitting any packets. - When looking up DAD queue entries for an incoming NS or NA, don't bother fiddling with the DAD queue entry reference count. - Split nd6_dad_starttimer() so that the caller is responsible to transmitting a NS if it so desires. - Remove the DAD entry from the queue before stopping the timer. Use a temporary reference to make sure that the entry doesn't get freed by the callout while we're draining.