Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet6/nd6_nbr.c
Show First 20 Lines • Show All 1,114 Lines • ▼ Show 20 Lines | struct dadq { | ||||
int dad_ns_lcount; /* looped back NS */ | int dad_ns_lcount; /* looped back NS */ | ||||
int dad_loopbackprobe; /* probing state for loopback detection */ | int dad_loopbackprobe; /* probing state for loopback detection */ | ||||
struct callout dad_timer_ch; | struct callout dad_timer_ch; | ||||
struct vnet *dad_vnet; | struct vnet *dad_vnet; | ||||
u_int dad_refcnt; | u_int dad_refcnt; | ||||
#define ND_OPT_NONCE_LEN32 \ | #define ND_OPT_NONCE_LEN32 \ | ||||
((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t)) | ((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t)) | ||||
uint32_t dad_nonce[ND_OPT_NONCE_LEN32]; | uint32_t dad_nonce[ND_OPT_NONCE_LEN32]; | ||||
bool dad_ondadq; /* on dadq? Protected by DADQ_WLOCK. */ | |||||
}; | }; | ||||
static VNET_DEFINE(TAILQ_HEAD(, dadq), dadq); | static VNET_DEFINE(TAILQ_HEAD(, dadq), dadq); | ||||
static VNET_DEFINE(struct rwlock, dad_rwlock); | static VNET_DEFINE(struct rwlock, dad_rwlock); | ||||
#define V_dadq VNET(dadq) | #define V_dadq VNET(dadq) | ||||
#define V_dad_rwlock VNET(dad_rwlock) | #define V_dad_rwlock VNET(dad_rwlock) | ||||
#define DADQ_RLOCK() rw_rlock(&V_dad_rwlock) | #define DADQ_RLOCK() rw_rlock(&V_dad_rwlock) | ||||
#define DADQ_RUNLOCK() rw_runlock(&V_dad_rwlock) | #define DADQ_RUNLOCK() rw_runlock(&V_dad_rwlock) | ||||
#define DADQ_WLOCK() rw_wlock(&V_dad_rwlock) | #define DADQ_WLOCK() rw_wlock(&V_dad_rwlock) | ||||
#define DADQ_WUNLOCK() rw_wunlock(&V_dad_rwlock) | #define DADQ_WUNLOCK() rw_wunlock(&V_dad_rwlock) | ||||
static void | static void | ||||
nd6_dad_add(struct dadq *dp) | nd6_dad_add(struct dadq *dp) | ||||
{ | { | ||||
DADQ_WLOCK(); | DADQ_WLOCK(); | ||||
TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list); | TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list); | ||||
dp->dad_ondadq = true; | |||||
DADQ_WUNLOCK(); | DADQ_WUNLOCK(); | ||||
} | } | ||||
static void | static void | ||||
nd6_dad_del(struct dadq *dp) | nd6_dad_del(struct dadq *dp) | ||||
{ | { | ||||
DADQ_WLOCK(); | DADQ_WLOCK(); | ||||
if (dp->dad_ondadq) { | |||||
/* | |||||
* Remove dp from the dadq and release the dadq's | |||||
* reference. | |||||
*/ | |||||
TAILQ_REMOVE(&V_dadq, dp, dad_list); | TAILQ_REMOVE(&V_dadq, dp, dad_list); | ||||
dp->dad_ondadq = false; | |||||
DADQ_WUNLOCK(); | DADQ_WUNLOCK(); | ||||
nd6_dad_rele(dp); | nd6_dad_rele(dp); | ||||
} else | |||||
DADQ_WUNLOCK(); | |||||
} | } | ||||
static struct dadq * | static struct dadq * | ||||
nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n) | nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n) | ||||
{ | { | ||||
struct dadq *dp; | struct dadq *dp; | ||||
DADQ_RLOCK(); | DADQ_RLOCK(); | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | #endif | ||||
* (re)initialization. | * (re)initialization. | ||||
*/ | */ | ||||
dp->dad_ifa = ifa; | dp->dad_ifa = ifa; | ||||
ifa_ref(dp->dad_ifa); | ifa_ref(dp->dad_ifa); | ||||
dp->dad_count = V_ip6_dad_count; | dp->dad_count = V_ip6_dad_count; | ||||
dp->dad_ns_icount = dp->dad_na_icount = 0; | dp->dad_ns_icount = dp->dad_na_icount = 0; | ||||
dp->dad_ns_ocount = dp->dad_ns_tcount = 0; | dp->dad_ns_ocount = dp->dad_ns_tcount = 0; | ||||
dp->dad_ns_lcount = dp->dad_loopbackprobe = 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); | refcount_init(&dp->dad_refcnt, 1); | ||||
nd6_dad_add(dp); | nd6_dad_add(dp); | ||||
nd6_dad_starttimer(dp, delay, 0); | nd6_dad_starttimer(dp, delay, 0); | ||||
} | } | ||||
/* | /* | ||||
* terminate DAD unconditionally. used for address removals. | * terminate DAD unconditionally. used for address removals. | ||||
*/ | */ | ||||
void | void | ||||
nd6_dad_stop(struct ifaddr *ifa) | nd6_dad_stop(struct ifaddr *ifa) | ||||
{ | { | ||||
struct dadq *dp; | struct dadq *dp; | ||||
dp = nd6_dad_find(ifa, NULL); | dp = nd6_dad_find(ifa, NULL); | ||||
if (!dp) { | if (!dp) { | ||||
/* DAD wasn't started yet */ | /* DAD wasn't started yet */ | ||||
return; | return; | ||||
} | } | ||||
nd6_dad_stoptimer(dp); | 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); | nd6_dad_del(dp); | ||||
/* Release this function's reference, acquired by nd6_dad_find(). */ | |||||
nd6_dad_rele(dp); | nd6_dad_rele(dp); | ||||
} | } | ||||
static void | static void | ||||
nd6_dad_timer(struct dadq *dp) | nd6_dad_timer(struct dadq *dp) | ||||
{ | { | ||||
CURVNET_SET(dp->dad_vnet); | CURVNET_SET(dp->dad_vnet); | ||||
struct ifaddr *ifa = dp->dad_ifa; | struct ifaddr *ifa = dp->dad_ifa; | ||||
▲ Show 20 Lines • Show All 225 Lines • Show Last 20 Lines |