Module Name: src Committed By: roy Date: Fri Dec 7 14:47:24 UTC 2018
Modified Files: src/sys/netinet6: nd6_nbr.c Log Message: inet6: match NS nonce to any interface This allows the same address to exist on many interfaces on the same prefix, matching the inet behaviour. To generate a diff of this commit: cvs rdiff -u -r1.161 -r1.162 src/sys/netinet6/nd6_nbr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet6/nd6_nbr.c diff -u src/sys/netinet6/nd6_nbr.c:1.161 src/sys/netinet6/nd6_nbr.c:1.162 --- src/sys/netinet6/nd6_nbr.c:1.161 Tue Dec 4 21:16:54 2018 +++ src/sys/netinet6/nd6_nbr.c Fri Dec 7 14:47:24 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_nbr.c,v 1.161 2018/12/04 21:16:54 roy Exp $ */ +/* $NetBSD: nd6_nbr.c,v 1.162 2018/12/07 14:47:24 roy Exp $ */ /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.161 2018/12/04 21:16:54 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.162 2018/12/07 14:47:24 roy Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -77,6 +77,7 @@ __KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v struct dadq; static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *, bool *); +static bool nd6_dad_ownnonce(struct ifaddr *, struct nd_opt_nonce *nonce); static void nd6_dad_starttimer(struct dadq *, int); static void nd6_dad_destroytimer(struct dadq *); static void nd6_dad_timer(struct dadq *); @@ -309,6 +310,16 @@ nd6_ns_input(struct mbuf *m, int off, in goto freeit; } + /* + * It looks that sender is performing DAD. + * Check that the nonce is not being used by the same address + * on another interface. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&saddr6) && ndopts.nd_opts_nonce != NULL) { + if (nd6_dad_ownnonce(ifa, ndopts.nd_opts_nonce)) + goto freeit; + } + ifa_release(ifa, &psref_ia); ifa = NULL; @@ -1088,17 +1099,33 @@ static kmutex_t nd6_dad_lock; static struct dadq * nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *nonce, bool *found_nonce) { + struct in6_addr *myaddr6, *dadaddr6; + bool match_ifa; struct dadq *dp; int i, nonce_max; KASSERT(mutex_owned(&nd6_dad_lock)); + KASSERT(ifa != NULL); + + myaddr6 = IFA_IN6(ifa); + if (nonce != NULL && + nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8) + nonce = NULL; + match_ifa = nonce == NULL || found_nonce == NULL || *found_nonce == false; + if (found_nonce != NULL) + *found_nonce = false; TAILQ_FOREACH(dp, &dadq, dad_list) { - if (dp->dad_ifa != ifa) - continue; + if (match_ifa) { + if (dp->dad_ifa != ifa) + continue; + } else { + dadaddr6 = IFA_IN6(dp->dad_ifa); + if (!IN6_ARE_ADDR_EQUAL(myaddr6, dadaddr6)) + continue; + } - if (nonce == NULL || - nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8) + if (nonce == NULL) break; nonce_max = MIN(dp->dad_ns_ocount, ND_OPT_NONCE_STORE); @@ -1115,7 +1142,7 @@ nd6_dad_find(struct ifaddr *ifa, struct log(LOG_DEBUG, "%s: detected a looped back NS message for %s\n", ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???", - IN6_PRINT(ip6buf, IFA_IN6(ifa))); + IN6_PRINT(ip6buf, myaddr6)); dp->dad_ns_lcount++; continue; } @@ -1125,6 +1152,18 @@ nd6_dad_find(struct ifaddr *ifa, struct return dp; } +static bool +nd6_dad_ownnonce(struct ifaddr *ifa, struct nd_opt_nonce *nonce) +{ + bool found_nonce = true; + + mutex_enter(&nd6_dad_lock); + nd6_dad_find(ifa, nonce, &found_nonce); + mutex_exit(&nd6_dad_lock); + + return found_nonce; +} + static void nd6_dad_starttimer(struct dadq *dp, int ticks) {