version 1.61, 2006/03/03 14:07:06 |
version 1.62, 2006/03/05 23:47:08 |
Line 58 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 58 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <netinet/in_var.h> |
#include <netinet/in_var.h> |
#include <netinet6/in6_var.h> |
#include <netinet6/in6_var.h> |
|
#include <netinet6/in6_ifattach.h> |
#include <netinet/ip6.h> |
#include <netinet/ip6.h> |
#include <netinet6/ip6_var.h> |
#include <netinet6/ip6_var.h> |
#include <netinet6/scope6_var.h> |
#include <netinet6/scope6_var.h> |
Line 173 nd6_ns_input(m, off, icmp6len) |
|
Line 174 nd6_ns_input(m, off, icmp6len) |
|
* Attaching target link-layer address to the NA? |
* Attaching target link-layer address to the NA? |
* (RFC 2461 7.2.4) |
* (RFC 2461 7.2.4) |
* |
* |
* NS IP dst is unicast/anycast MUST NOT add |
* NS IP dst is multicast MUST add |
* NS IP dst is solicited-node multicast MUST add |
* Otherwise MAY be omitted |
* |
* |
* In implementation, we add target link-layer address by default. |
* In this implementation, we omit the target link-layer address |
* We do not add one in MUST NOT cases. |
* in the "MAY" case. |
*/ |
*/ |
#if 0 /* too much! */ |
#if 0 /* too much! */ |
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6); |
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6); |
Line 200 nd6_ns_input(m, off, icmp6len) |
|
Line 201 nd6_ns_input(m, off, icmp6len) |
|
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); |
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); |
|
|
/* (2) check. */ |
/* (2) check. */ |
if (!ifa) { |
if (ifa == NULL) { |
struct rtentry *rt; |
struct rtentry *rt; |
struct sockaddr_in6 tsin6; |
struct sockaddr_in6 tsin6; |
|
|
bzero(&tsin6, sizeof tsin6); |
memset(&tsin6, 0, sizeof(tsin6)); |
tsin6.sin6_len = sizeof(struct sockaddr_in6); |
tsin6.sin6_len = sizeof(struct sockaddr_in6); |
tsin6.sin6_family = AF_INET6; |
tsin6.sin6_family = AF_INET6; |
tsin6.sin6_addr = taddr6; |
tsin6.sin6_addr = taddr6; |
Line 226 nd6_ns_input(m, off, icmp6len) |
|
Line 227 nd6_ns_input(m, off, icmp6len) |
|
if (rt) |
if (rt) |
rtfree(rt); |
rtfree(rt); |
} |
} |
if (!ifa) { |
if (ifa == NULL) { |
/* |
/* |
* We've got an NS packet, and we don't have that address |
* We've got an NS packet, and we don't have that address |
* assigned for us. We MUST silently ignore it. |
* assigned for us. We MUST silently ignore it. |
Line 424 nd6_ns_output(ifp, daddr6, taddr6, ln, d |
|
Line 425 nd6_ns_output(ifp, daddr6, taddr6, ln, d |
|
struct in6_addr *hsrc = NULL; |
struct in6_addr *hsrc = NULL; |
|
|
if (ln && ln->ln_hold) { |
if (ln && ln->ln_hold) { |
|
/* |
|
* assuming every packet in ln_hold has the same IP |
|
* header |
|
*/ |
hip6 = mtod(ln->ln_hold, struct ip6_hdr *); |
hip6 = mtod(ln->ln_hold, struct ip6_hdr *); |
/* XXX pullup? */ |
/* XXX pullup? */ |
if (sizeof(*hip6) < ln->ln_hold->m_len) |
if (sizeof(*hip6) < ln->ln_hold->m_len) |
Line 685 nd6_na_input(m, off, icmp6len) |
|
Line 690 nd6_na_input(m, off, icmp6len) |
|
/* |
/* |
* Check if the link-layer address has changed or not. |
* Check if the link-layer address has changed or not. |
*/ |
*/ |
if (!lladdr) |
if (lladdr == NULL) |
llchange = 0; |
llchange = 0; |
else { |
else { |
if (sdl->sdl_alen) { |
if (sdl->sdl_alen) { |
Line 716 nd6_na_input(m, off, icmp6len) |
|
Line 721 nd6_na_input(m, off, icmp6len) |
|
* 1 1 y n (2a) L *->REACHABLE |
* 1 1 y n (2a) L *->REACHABLE |
* 1 1 y y (2a) L *->REACHABLE |
* 1 1 y y (2a) L *->REACHABLE |
*/ |
*/ |
if (!is_override && (lladdr && llchange)) { /* (1) */ |
if (!is_override && lladdr != NULL && llchange) { /* (1) */ |
/* |
/* |
* If state is REACHABLE, make it STALE. |
* If state is REACHABLE, make it STALE. |
* no other updates should be done. |
* no other updates should be done. |
Line 727 nd6_na_input(m, off, icmp6len) |
|
Line 732 nd6_na_input(m, off, icmp6len) |
|
} |
} |
goto freeit; |
goto freeit; |
} else if (is_override /* (2a) */ |
} else if (is_override /* (2a) */ |
|| (!is_override && (lladdr && !llchange)) /* (2b) */ |
|| (!is_override && lladdr != NULL && !llchange) /* (2b) */ |
|| !lladdr) { /* (2c) */ |
|| lladdr == NULL) { /* (2c) */ |
/* |
/* |
* Update link-local address, if any. |
* Update link-local address, if any. |
*/ |
*/ |
if (lladdr) { |
if (lladdr != NULL) { |
sdl->sdl_alen = ifp->if_addrlen; |
sdl->sdl_alen = ifp->if_addrlen; |
bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); |
bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); |
} |
} |
Line 797 nd6_na_input(m, off, icmp6len) |
|
Line 802 nd6_na_input(m, off, icmp6len) |
|
rt->rt_flags &= ~RTF_REJECT; |
rt->rt_flags &= ~RTF_REJECT; |
ln->ln_asked = 0; |
ln->ln_asked = 0; |
if (ln->ln_hold) { |
if (ln->ln_hold) { |
/* |
struct mbuf *m_hold, *m_hold_next; |
* we assume ifp is not a loopback here, so just set the 2nd |
|
* argument as the 1st one. |
for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { |
*/ |
struct mbuf *mpkt = NULL; |
nd6_output(ifp, ifp, ln->ln_hold, |
|
(struct sockaddr_in6 *)rt_key(rt), rt); |
m_hold_next = m_hold->m_nextpkt; |
ln->ln_hold = NULL; |
mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT); |
|
if (mpkt == NULL) { |
|
m_freem(m_hold); |
|
break; |
|
} |
|
mpkt->m_nextpkt = NULL; |
|
/* |
|
* we assume ifp is not a loopback here, so just set |
|
* the 2nd argument as the 1st one. |
|
*/ |
|
nd6_output(ifp, ifp, mpkt, |
|
(struct sockaddr_in6 *)rt_key(rt), rt); |
|
} |
|
ln->ln_hold = NULL; |
} |
} |
|
|
freeit: |
freeit: |
Line 1056 nd6_dad_stoptimer(dp) |
|
Line 1074 nd6_dad_stoptimer(dp) |
|
* Start Duplicate Address Detection (DAD) for specified interface address. |
* Start Duplicate Address Detection (DAD) for specified interface address. |
*/ |
*/ |
void |
void |
nd6_dad_start(ifa, xtick) |
nd6_dad_start(ifa, delay) |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
int *xtick; /* minimum delay ticks for IFF_UP event */ |
int delay; /* minimum delay ticks for IFF_UP event */ |
{ |
{ |
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; |
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; |
struct dadq *dp; |
struct dadq *dp; |
Line 1090 nd6_dad_start(ifa, xtick) |
|
Line 1108 nd6_dad_start(ifa, xtick) |
|
ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
return; |
return; |
} |
} |
if (!ifa->ifa_ifp) |
if (ifa->ifa_ifp == NULL) |
panic("nd6_dad_start: ifa->ifa_ifp == NULL"); |
panic("nd6_dad_start: ifa->ifa_ifp == NULL"); |
if (!(ifa->ifa_ifp->if_flags & IFF_UP)) |
if (!(ifa->ifa_ifp->if_flags & IFF_UP)) |
return; |
return; |
Line 1125 nd6_dad_start(ifa, xtick) |
|
Line 1143 nd6_dad_start(ifa, xtick) |
|
dp->dad_count = ip6_dad_count; |
dp->dad_count = 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; |
if (xtick == NULL) { |
if (delay == 0) { |
nd6_dad_ns_output(dp, ifa); |
nd6_dad_ns_output(dp, ifa); |
nd6_dad_starttimer(dp, |
nd6_dad_starttimer(dp, |
(long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); |
(long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); |
} else { |
} else |
int ntick; |
nd6_dad_starttimer(dp, delay); |
|
|
if (*xtick == 0) |
|
ntick = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); |
|
else |
|
ntick = *xtick + arc4random() % (hz / 2); |
|
*xtick = ntick; |
|
nd6_dad_starttimer(dp, ntick); |
|
} |
|
} |
} |
|
|
/* |
/* |
Line 1153 nd6_dad_stop(ifa) |
|
Line 1163 nd6_dad_stop(ifa) |
|
if (!dad_init) |
if (!dad_init) |
return; |
return; |
dp = nd6_dad_find(ifa); |
dp = nd6_dad_find(ifa); |
if (!dp) { |
if (dp == NULL) { |
/* DAD wasn't started yet */ |
/* DAD wasn't started yet */ |
return; |
return; |
} |
} |
Line 1275 nd6_dad_duplicated(ifa) |
|
Line 1285 nd6_dad_duplicated(ifa) |
|
struct ifaddr *ifa; |
struct ifaddr *ifa; |
{ |
{ |
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; |
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; |
|
struct ifnet *ifp; |
struct dadq *dp; |
struct dadq *dp; |
|
|
dp = nd6_dad_find(ifa); |
dp = nd6_dad_find(ifa); |
Line 1283 nd6_dad_duplicated(ifa) |
|
Line 1294 nd6_dad_duplicated(ifa) |
|
return; |
return; |
} |
} |
|
|
|
ifp = ifa->ifa_ifp; |
log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " |
log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " |
"NS in/out=%d/%d, NA in=%d\n", |
"NS in/out=%d/%d, NA in=%d\n", |
if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr), |
if_name(ifp), ip6_sprintf(&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_na_icount); |
|
|
ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
ia->ia6_flags &= ~IN6_IFF_TENTATIVE; |
Line 1295 nd6_dad_duplicated(ifa) |
|
Line 1307 nd6_dad_duplicated(ifa) |
|
nd6_dad_stoptimer(dp); |
nd6_dad_stoptimer(dp); |
|
|
log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n", |
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", |
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); |
TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list); |
free(dp, M_IP6NDP); |
free(dp, M_IP6NDP); |
Line 1340 nd6_dad_ns_input(ifa) |
|
Line 1386 nd6_dad_ns_input(ifa) |
|
struct dadq *dp; |
struct dadq *dp; |
int duplicate; |
int duplicate; |
|
|
if (!ifa) |
if (ifa == NULL) |
panic("ifa == NULL in nd6_dad_ns_input"); |
panic("ifa == NULL in nd6_dad_ns_input"); |
|
|
ia = (struct in6_ifaddr *)ifa; |
ia = (struct in6_ifaddr *)ifa; |
Line 1361 nd6_dad_ns_input(ifa) |
|
Line 1407 nd6_dad_ns_input(ifa) |
|
* if I'm yet to start DAD, someone else started using this address |
* if I'm yet to start DAD, someone else started using this address |
* first. I have a duplicate and you win. |
* first. I have a duplicate and you win. |
*/ |
*/ |
if (!dp || dp->dad_ns_ocount == 0) |
if (dp == NULL || dp->dad_ns_ocount == 0) |
duplicate++; |
duplicate++; |
|
|
/* XXX more checks for loopback situation - see nd6_dad_timer too */ |
/* XXX more checks for loopback situation - see nd6_dad_timer too */ |
Line 1385 nd6_dad_na_input(ifa) |
|
Line 1431 nd6_dad_na_input(ifa) |
|
{ |
{ |
struct dadq *dp; |
struct dadq *dp; |
|
|
if (!ifa) |
if (ifa == NULL) |
panic("ifa == NULL in nd6_dad_na_input"); |
panic("ifa == NULL in nd6_dad_na_input"); |
|
|
dp = nd6_dad_find(ifa); |
dp = nd6_dad_find(ifa); |