Implement Enhanced DAD algorithm for IPv6 described in
draft-ietf-6man-enhanced-dad-13. This basically adds a random nonce option (RFC 3971) to NS messages for DAD probe to detect a looped back packet. This looped back packet prevented DAD on some pseudo-interfaces which aggregates multiple L2 links such as lagg(4). The length of the nonce is set to 6 bytes. This algorithm can be disabled by setting net.inet6.ip6.dad_enhanced sysctl to 0 in a per-vnet basis. Reported by: hiren Reviewed by: ae Differential Revision: https://reviews.freebsd.org/D1835
This commit is contained in:
parent
1d0f6813ac
commit
11d8451df3
@ -297,9 +297,11 @@ struct nd_opt_hdr { /* Neighbor discovery option header */
|
||||
#define ND_OPT_PREFIX_INFORMATION 3
|
||||
#define ND_OPT_REDIRECTED_HEADER 4
|
||||
#define ND_OPT_MTU 5
|
||||
#define ND_OPT_NONCE 14 /* RFC 3971 */
|
||||
#define ND_OPT_ROUTE_INFO 24 /* RFC 4191 */
|
||||
#define ND_OPT_RDNSS 25 /* RFC 6106 */
|
||||
#define ND_OPT_DNSSL 31 /* RFC 6106 */
|
||||
#define ND_OPT_MAX 31
|
||||
|
||||
struct nd_opt_prefix_info { /* prefix information */
|
||||
u_int8_t nd_opt_pi_type;
|
||||
@ -330,6 +332,16 @@ struct nd_opt_mtu { /* MTU option */
|
||||
u_int32_t nd_opt_mtu_mtu;
|
||||
} __packed;
|
||||
|
||||
#define ND_OPT_NONCE_LEN ((1 * 8) - 2)
|
||||
#if ((ND_OPT_NONCE_LEN + 2) % 8) != 0
|
||||
#error "(ND_OPT_NONCE_LEN + 2) must be a multiple of 8."
|
||||
#endif
|
||||
struct nd_opt_nonce { /* nonce option */
|
||||
u_int8_t nd_opt_nonce_type;
|
||||
u_int8_t nd_opt_nonce_len;
|
||||
u_int8_t nd_opt_nonce[ND_OPT_NONCE_LEN];
|
||||
} __packed;
|
||||
|
||||
struct nd_opt_route_info { /* route info */
|
||||
u_int8_t nd_opt_rti_type;
|
||||
u_int8_t nd_opt_rti_len;
|
||||
|
@ -372,6 +372,7 @@ nd6_options(union nd_opts *ndopts)
|
||||
case ND_OPT_TARGET_LINKADDR:
|
||||
case ND_OPT_MTU:
|
||||
case ND_OPT_REDIRECTED_HEADER:
|
||||
case ND_OPT_NONCE:
|
||||
if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
|
||||
nd6log((LOG_INFO,
|
||||
"duplicated ND6 option found (type=%d)\n",
|
||||
@ -526,7 +527,7 @@ nd6_llinfo_timer(void *arg)
|
||||
ln->la_asked++;
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(ln);
|
||||
nd6_ns_output(ifp, NULL, dst, ln, 0);
|
||||
nd6_ns_output(ifp, NULL, dst, ln, NULL);
|
||||
LLE_WLOCK(ln);
|
||||
} else {
|
||||
struct mbuf *m = ln->la_hold;
|
||||
@ -573,7 +574,7 @@ nd6_llinfo_timer(void *arg)
|
||||
ln->ln_state = ND6_LLINFO_PROBE;
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(ln);
|
||||
nd6_ns_output(ifp, dst, dst, ln, 0);
|
||||
nd6_ns_output(ifp, dst, dst, ln, NULL);
|
||||
LLE_WLOCK(ln);
|
||||
} else {
|
||||
ln->ln_state = ND6_LLINFO_STALE; /* XXX */
|
||||
@ -585,7 +586,7 @@ nd6_llinfo_timer(void *arg)
|
||||
ln->la_asked++;
|
||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(ln);
|
||||
nd6_ns_output(ifp, dst, dst, ln, 0);
|
||||
nd6_ns_output(ifp, dst, dst, ln, NULL);
|
||||
LLE_WLOCK(ln);
|
||||
} else {
|
||||
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
|
||||
@ -2084,7 +2085,7 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
|
||||
nd6_llinfo_settimer_locked(lle,
|
||||
(long)ND_IFINFO(ifp)->retrans * hz / 1000);
|
||||
LLE_WUNLOCK(lle);
|
||||
nd6_ns_output(ifp, NULL, &dst->sin6_addr, lle, 0);
|
||||
nd6_ns_output(ifp, NULL, &dst->sin6_addr, lle, NULL);
|
||||
} else {
|
||||
/* We did the lookup so we need to do the unlock here. */
|
||||
LLE_WUNLOCK(lle);
|
||||
|
@ -359,7 +359,7 @@ VNET_DECLARE(int, ip6_temp_regen_advance); /* seconds */
|
||||
#define V_ip6_temp_regen_advance VNET(ip6_temp_regen_advance)
|
||||
|
||||
union nd_opts {
|
||||
struct nd_opt_hdr *nd_opt_array[8]; /* max = target address list */
|
||||
struct nd_opt_hdr *nd_opt_array[16]; /* max = ND_OPT_NONCE */
|
||||
struct {
|
||||
struct nd_opt_hdr *zero;
|
||||
struct nd_opt_hdr *src_lladdr;
|
||||
@ -367,6 +367,16 @@ union nd_opts {
|
||||
struct nd_opt_prefix_info *pi_beg; /* multiple opts, start */
|
||||
struct nd_opt_rd_hdr *rh;
|
||||
struct nd_opt_mtu *mtu;
|
||||
struct nd_opt_hdr *__res6;
|
||||
struct nd_opt_hdr *__res7;
|
||||
struct nd_opt_hdr *__res8;
|
||||
struct nd_opt_hdr *__res9;
|
||||
struct nd_opt_hdr *__res10;
|
||||
struct nd_opt_hdr *__res11;
|
||||
struct nd_opt_hdr *__res12;
|
||||
struct nd_opt_hdr *__res13;
|
||||
struct nd_opt_nonce *nonce;
|
||||
struct nd_opt_hdr *__res15;
|
||||
struct nd_opt_hdr *search; /* multiple opts */
|
||||
struct nd_opt_hdr *last; /* multiple opts */
|
||||
int done;
|
||||
@ -379,6 +389,7 @@ union nd_opts {
|
||||
#define nd_opts_pi_end nd_opt_each.pi_end
|
||||
#define nd_opts_rh nd_opt_each.rh
|
||||
#define nd_opts_mtu nd_opt_each.mtu
|
||||
#define nd_opts_nonce nd_opt_each.nonce
|
||||
#define nd_opts_search nd_opt_each.search
|
||||
#define nd_opts_last nd_opt_each.last
|
||||
#define nd_opts_done nd_opt_each.done
|
||||
@ -425,7 +436,7 @@ void nd6_na_output(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, u_long, int, struct sockaddr *);
|
||||
void nd6_ns_input(struct mbuf *, int, int);
|
||||
void nd6_ns_output(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, struct llentry *, int);
|
||||
const struct in6_addr *, struct llentry *, uint8_t *);
|
||||
caddr_t nd6_ifptomac(struct ifnet *);
|
||||
void nd6_dad_init(void);
|
||||
void nd6_dad_start(struct ifaddr *, int);
|
||||
|
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/mbuf.h>
|
||||
@ -48,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/callout.h>
|
||||
@ -61,6 +63,7 @@ __FBSDID("$FreeBSD$");
|
||||
#ifdef RADIX_MPATH
|
||||
#include <net/radix_mpath.h>
|
||||
#endif
|
||||
#include <net/vnet.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_var.h>
|
||||
@ -79,7 +82,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define SDL(s) ((struct sockaddr_dl *)s)
|
||||
|
||||
struct dadq;
|
||||
static struct dadq *nd6_dad_find(struct ifaddr *);
|
||||
static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *);
|
||||
static void nd6_dad_add(struct dadq *dp);
|
||||
static void nd6_dad_del(struct dadq *dp);
|
||||
static void nd6_dad_rele(struct dadq *);
|
||||
@ -88,16 +91,21 @@ static void nd6_dad_stoptimer(struct dadq *);
|
||||
static void nd6_dad_timer(struct dadq *);
|
||||
static void nd6_dad_duplicated(struct ifaddr *, struct dadq *);
|
||||
static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
|
||||
static void nd6_dad_ns_input(struct ifaddr *);
|
||||
static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *);
|
||||
static void nd6_dad_na_input(struct ifaddr *);
|
||||
static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
|
||||
const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
|
||||
|
||||
static VNET_DEFINE(int, dad_ignore_ns) = 0; /* ignore NS in DAD
|
||||
- specwise incorrect */
|
||||
static VNET_DEFINE(int, dad_enhanced) = 1;
|
||||
#define V_dad_enhanced VNET(dad_enhanced)
|
||||
|
||||
SYSCTL_DECL(_net_inet6_ip6);
|
||||
SYSCTL_INT(_net_inet6_ip6, OID_AUTO, dad_enhanced, CTLFLAG_VNET | CTLFLAG_RW,
|
||||
&VNET_NAME(dad_enhanced), 0,
|
||||
"Enable Enhanced DAD, which adds a random nonce to NS messages for DAD.");
|
||||
|
||||
static VNET_DEFINE(int, dad_maxtry) = 15; /* max # of *tries* to
|
||||
transmit DAD packet */
|
||||
#define V_dad_ignore_ns VNET(dad_ignore_ns)
|
||||
#define V_dad_maxtry VNET(dad_maxtry)
|
||||
|
||||
/*
|
||||
@ -321,7 +329,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
|
||||
* silently ignore it.
|
||||
*/
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
|
||||
nd6_dad_ns_input(ifa);
|
||||
nd6_dad_ns_input(ifa, ndopts.nd_opts_nonce);
|
||||
|
||||
goto freeit;
|
||||
}
|
||||
@ -382,12 +390,13 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
|
||||
* Based on RFC 2461
|
||||
* Based on RFC 2462 (duplicate address detection)
|
||||
*
|
||||
* ln - for source address determination
|
||||
* dad - duplicate address detection
|
||||
* ln - for source address determination
|
||||
* nonce - If non-NULL, NS is used for duplicate address detection and
|
||||
* the value (length is ND_OPT_NONCE_LEN) is used as a random nonce.
|
||||
*/
|
||||
void
|
||||
nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
const struct in6_addr *taddr6, struct llentry *ln, int dad)
|
||||
const struct in6_addr *taddr6, struct llentry *ln, uint8_t *nonce)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct m_tag *mtag;
|
||||
@ -453,7 +462,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
|
||||
goto bad;
|
||||
}
|
||||
if (!dad) {
|
||||
if (nonce == NULL) {
|
||||
struct ifaddr *ifa;
|
||||
|
||||
/*
|
||||
@ -550,7 +559,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
* Multicast NS MUST add one add the option
|
||||
* Unicast NS SHOULD add one add the option
|
||||
*/
|
||||
if (!dad && (mac = nd6_ifptomac(ifp))) {
|
||||
if (nonce == NULL && (mac = nd6_ifptomac(ifp))) {
|
||||
int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
|
||||
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
|
||||
/* 8 byte alignments... */
|
||||
@ -564,7 +573,26 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
nd_opt->nd_opt_len = optlen >> 3;
|
||||
bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
|
||||
}
|
||||
/*
|
||||
* Add a Nonce option (RFC 3971) to detect looped back NS messages.
|
||||
* This behavior is documented as Enhanced Duplicate Address
|
||||
* Detection in draft-ietf-6man-enhanced-dad-13.
|
||||
* net.inet6.ip6.dad_enhanced=0 disables this.
|
||||
*/
|
||||
if (V_dad_enhanced != 0 && nonce != NULL) {
|
||||
int optlen = sizeof(struct nd_opt_hdr) + ND_OPT_NONCE_LEN;
|
||||
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
|
||||
/* 8-byte alignment is required. */
|
||||
optlen = (optlen + 7) & ~7;
|
||||
|
||||
m->m_pkthdr.len += optlen;
|
||||
m->m_len += optlen;
|
||||
icmp6len += optlen;
|
||||
bzero((caddr_t)nd_opt, optlen);
|
||||
nd_opt->nd_opt_type = ND_OPT_NONCE;
|
||||
nd_opt->nd_opt_len = optlen >> 3;
|
||||
bcopy(nonce, (caddr_t)(nd_opt + 1), ND_OPT_NONCE_LEN);
|
||||
}
|
||||
ip6->ip6_plen = htons((u_short)icmp6len);
|
||||
nd_ns->nd_ns_cksum = 0;
|
||||
nd_ns->nd_ns_cksum =
|
||||
@ -579,7 +607,8 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
m_tag_prepend(m, mtag);
|
||||
}
|
||||
|
||||
ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL);
|
||||
ip6_output(m, NULL, &ro, (nonce != NULL) ? IPV6_UNSPECSRC : 0,
|
||||
&im6o, NULL, NULL);
|
||||
icmp6_ifstat_inc(ifp, ifs6_out_msg);
|
||||
icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
|
||||
ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
|
||||
@ -1139,9 +1168,13 @@ struct dadq {
|
||||
int dad_ns_ocount; /* NS sent so far */
|
||||
int dad_ns_icount;
|
||||
int dad_na_icount;
|
||||
int dad_ns_lcount; /* looped back NS */
|
||||
struct callout dad_timer_ch;
|
||||
struct vnet *dad_vnet;
|
||||
u_int dad_refcnt;
|
||||
#define ND_OPT_NONCE_LEN32 \
|
||||
((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t))
|
||||
uint32_t dad_nonce[ND_OPT_NONCE_LEN32];
|
||||
};
|
||||
|
||||
static VNET_DEFINE(TAILQ_HEAD(, dadq), dadq);
|
||||
@ -1174,16 +1207,34 @@ nd6_dad_del(struct dadq *dp)
|
||||
}
|
||||
|
||||
static struct dadq *
|
||||
nd6_dad_find(struct ifaddr *ifa)
|
||||
nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n)
|
||||
{
|
||||
struct dadq *dp;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
|
||||
DADQ_RLOCK();
|
||||
TAILQ_FOREACH(dp, &V_dadq, dad_list)
|
||||
if (dp->dad_ifa == ifa) {
|
||||
refcount_acquire(&dp->dad_refcnt);
|
||||
break;
|
||||
TAILQ_FOREACH(dp, &V_dadq, dad_list) {
|
||||
if (dp->dad_ifa != ifa)
|
||||
continue;
|
||||
/*
|
||||
* Skip if the nonce matches the received one.
|
||||
* +2 in the length is required because of type and
|
||||
* length fields are included in a header.
|
||||
*/
|
||||
if (n != NULL &&
|
||||
n->nd_opt_nonce_len == (ND_OPT_NONCE_LEN + 2) / 8 &&
|
||||
memcmp(&n->nd_opt_nonce[0], &dp->dad_nonce[0],
|
||||
ND_OPT_NONCE_LEN) == 0) {
|
||||
log(LOG_ERR, "%s: a looped back NS message is "
|
||||
"detected during DAD for %s.\n",
|
||||
if_name(ifa->ifa_ifp),
|
||||
ip6_sprintf(ip6buf, IFA_IN6(ifa)));
|
||||
dp->dad_ns_lcount++;
|
||||
continue;
|
||||
}
|
||||
refcount_acquire(&dp->dad_refcnt);
|
||||
break;
|
||||
}
|
||||
DADQ_RUNLOCK();
|
||||
|
||||
return (dp);
|
||||
@ -1261,7 +1312,7 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
|
||||
}
|
||||
if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED)
|
||||
return;
|
||||
if ((dp = nd6_dad_find(ifa)) != NULL) {
|
||||
if ((dp = nd6_dad_find(ifa, NULL)) != NULL) {
|
||||
/* DAD already in progress */
|
||||
nd6_dad_rele(dp);
|
||||
return;
|
||||
@ -1293,6 +1344,7 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
|
||||
dp->dad_count = V_ip6_dad_count;
|
||||
dp->dad_ns_icount = dp->dad_na_icount = 0;
|
||||
dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
|
||||
dp->dad_ns_lcount = 0;
|
||||
refcount_init(&dp->dad_refcnt, 1);
|
||||
nd6_dad_add(dp);
|
||||
if (delay == 0) {
|
||||
@ -1312,7 +1364,7 @@ nd6_dad_stop(struct ifaddr *ifa)
|
||||
{
|
||||
struct dadq *dp;
|
||||
|
||||
dp = nd6_dad_find(ifa);
|
||||
dp = nd6_dad_find(ifa, NULL);
|
||||
if (!dp) {
|
||||
/* DAD wasn't started yet */
|
||||
return;
|
||||
@ -1325,7 +1377,7 @@ nd6_dad_stop(struct ifaddr *ifa)
|
||||
* we were waiting for it to stop, so re-do the lookup.
|
||||
*/
|
||||
nd6_dad_rele(dp);
|
||||
if (nd6_dad_find(ifa) == NULL)
|
||||
if (nd6_dad_find(ifa, NULL) == NULL)
|
||||
return;
|
||||
|
||||
nd6_dad_del(dp);
|
||||
@ -1421,9 +1473,10 @@ nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp)
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
|
||||
log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
|
||||
"NS in/out=%d/%d, NA in=%d\n",
|
||||
"NS in/out/loopback=%d/%d/%d, NA in=%d\n",
|
||||
if_name(ifa->ifa_ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
|
||||
dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
|
||||
dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_ns_lcount,
|
||||
dp->dad_na_icount);
|
||||
|
||||
ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
|
||||
ia->ia6_flags |= IN6_IFF_DUPLICATED;
|
||||
@ -1475,6 +1528,8 @@ nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
|
||||
{
|
||||
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
uint8_t *nonce;
|
||||
int i;
|
||||
|
||||
dp->dad_ns_tcount++;
|
||||
if ((ifp->if_flags & IFF_UP) == 0) {
|
||||
@ -1485,11 +1540,25 @@ nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
|
||||
}
|
||||
|
||||
dp->dad_ns_ocount++;
|
||||
nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
|
||||
if (V_dad_enhanced != 0) {
|
||||
for (i = 0; i < ND_OPT_NONCE_LEN32; i++)
|
||||
dp->dad_nonce[i] = arc4random();
|
||||
nonce = (uint8_t *)&dp->dad_nonce[0];
|
||||
/*
|
||||
* XXXHRS: Note that in the case that
|
||||
* DupAddrDetectTransmits > 1, multiple NS messages with
|
||||
* different nonces can be looped back in an unexpected
|
||||
* order. The current implementation recognizes only
|
||||
* the latest nonce on the sender side. Practically it
|
||||
* should work well in almost all cases.
|
||||
*/
|
||||
} else
|
||||
nonce = NULL;
|
||||
nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, nonce);
|
||||
}
|
||||
|
||||
static void
|
||||
nd6_dad_ns_input(struct ifaddr *ifa)
|
||||
nd6_dad_ns_input(struct ifaddr *ifa, struct nd_opt_nonce *ndopt_nonce)
|
||||
{
|
||||
struct in6_ifaddr *ia;
|
||||
struct ifnet *ifp;
|
||||
@ -1502,22 +1571,13 @@ nd6_dad_ns_input(struct ifaddr *ifa)
|
||||
ia = (struct in6_ifaddr *)ifa;
|
||||
ifp = ifa->ifa_ifp;
|
||||
taddr6 = &ia->ia_addr.sin6_addr;
|
||||
dp = nd6_dad_find(ifa);
|
||||
/* Ignore Nonce option when Enhanced DAD is disabled. */
|
||||
if (V_dad_enhanced == 0)
|
||||
ndopt_nonce = NULL;
|
||||
dp = nd6_dad_find(ifa, ndopt_nonce);
|
||||
if (dp == NULL)
|
||||
return;
|
||||
|
||||
/* Quickhack - completely ignore DAD NS packets */
|
||||
if (V_dad_ignore_ns) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_INFO,
|
||||
"nd6_dad_ns_input: ignoring DAD NS packet for "
|
||||
"address %s(%s)\n", ip6_sprintf(ip6buf, taddr6),
|
||||
if_name(ifa->ifa_ifp)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX more checks for loopback situation - see nd6_dad_timer too */
|
||||
|
||||
dp->dad_ns_icount++;
|
||||
nd6_dad_rele(dp);
|
||||
}
|
||||
@ -1530,7 +1590,7 @@ nd6_dad_na_input(struct ifaddr *ifa)
|
||||
if (ifa == NULL)
|
||||
panic("ifa == NULL in nd6_dad_na_input");
|
||||
|
||||
dp = nd6_dad_find(ifa);
|
||||
dp = nd6_dad_find(ifa, NULL);
|
||||
if (dp != NULL) {
|
||||
dp->dad_na_icount++;
|
||||
nd6_dad_rele(dp);
|
||||
|
Loading…
Reference in New Issue
Block a user