sync with KAME regarding the following clarification in RFC3542:

- disable IPv6 operation if DAD fails for some EUI-64 link-local addresses.
 - export get_hw_ifid() (and rename it) as a subroutine for this process.

Obtained from: KAME
Reviewd by: ume, gnn
MFC after: 2 week
This commit is contained in:
SUZUKI Shinsuke 2005-10-19 16:43:57 +00:00
parent 6b6c96661e
commit d28bde669a
3 changed files with 45 additions and 8 deletions

@ -75,7 +75,6 @@ extern struct inpcbinfo ripcbinfo;
static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));
static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
static int in6_ifattach_loopback __P((struct ifnet *));
@ -217,8 +216,8 @@ generate_tmp_ifid(seed0, seed1, ret)
* Get interface identifier for the specified interface.
* XXX assumes single sockaddr_dl (AF_LINK address) per an interface
*/
static int
get_hw_ifid(ifp, in6)
int
in6_get_hw_ifid(ifp, in6)
struct ifnet *ifp;
struct in6_addr *in6; /* upper 64bits are preserved */
{
@ -359,14 +358,14 @@ get_ifid(ifp0, altifp, in6)
struct ifnet *ifp;
/* first, try to get it from the interface itself */
if (get_hw_ifid(ifp0, in6) == 0) {
if (in6_get_hw_ifid(ifp0, in6) == 0) {
nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
if_name(ifp0)));
goto success;
}
/* try secondary EUI64 source. this basically is for ATM PVC */
if (altifp && get_hw_ifid(altifp, in6) == 0) {
if (altifp && in6_get_hw_ifid(altifp, in6) == 0) {
nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
if_name(ifp0), if_name(altifp)));
goto success;
@ -377,7 +376,7 @@ get_ifid(ifp0, altifp, in6)
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
if (ifp == ifp0)
continue;
if (get_hw_ifid(ifp, in6) != 0)
if (in6_get_hw_ifid(ifp, in6) != 0)
continue;
/*

@ -38,6 +38,7 @@ void in6_ifattach __P((struct ifnet *, struct ifnet *));
void in6_ifdetach __P((struct ifnet *));
void in6_get_tmpifid __P((struct ifnet *, u_int8_t *, const u_int8_t *, int));
void in6_tmpaddrtimer __P((void *));
int in6_get_hw_ifid __P((struct ifnet *, struct in6_addr *));
int in6_nigroup __P((struct ifnet *, const char *, int, struct in6_addr *));
#endif /* _KERNEL */

@ -57,6 +57,7 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#include <netinet6/in6_ifattach.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
@ -1306,6 +1307,7 @@ nd6_dad_duplicated(ifa)
struct ifaddr *ifa;
{
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
struct ifnet *ifp;
struct dadq *dp;
dp = nd6_dad_find(ifa);
@ -1325,10 +1327,45 @@ nd6_dad_duplicated(ifa)
/* We are done with DAD, with duplicate address found. (failure) */
nd6_dad_stoptimer(dp);
ifp = ifa->ifa_ifp;
log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
if_name(ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
log(LOG_ERR, "%s: manual intervention required\n",
if_name(ifa->ifa_ifp));
if_name(ifp));
/*
* If the address is a link-local address formed from an interface
* identifier based on the hardware address which is supposed to be
* uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP
* operation on the interface SHOULD be disabled.
* [rfc2462bis-03 Section 5.4.5]
*/
if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
struct in6_addr in6;
/*
* To avoid over-reaction, we only apply this logic when we are
* very sure that hardware addresses are supposed to be unique.
*/
switch (ifp->if_type) {
case IFT_ETHER:
case IFT_FDDI:
case IFT_ATM:
case IFT_IEEE1394:
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
in6 = ia->ia_addr.sin6_addr;
if (in6_get_hw_ifid(ifp, &in6) == 0 &&
IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
log(LOG_ERR, "%s: possible hardware address "
"duplication detected, disable IPv6\n",
if_name(ifp));
}
break;
}
}
TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
free(dp, M_IP6NDP);