sync with latest KAME in6_ifaddr/prefix/default router manipulation.

behavior changes:
- two iocts used by ndp(8) are now obsolete (backward compat provided).
  use sysctl path instead.
- lo0 does not get ::1 automatically.  it will get ::1 when lo0 comes up.
This commit is contained in:
itojun 2002-06-08 21:22:29 +00:00
parent 61ef51d198
commit 6d8d0d63d8
19 changed files with 2898 additions and 3031 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.532 2002/06/06 23:54:48 wrstuden Exp $
# $NetBSD: files,v 1.533 2002/06/08 21:22:29 itojun Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@ -1199,7 +1199,6 @@ file netinet6/in6_cksum.c inet6 & !inet6_md_cksum
file netinet6/in6_gif.c gif & inet6
file netinet6/in6_ifattach.c inet6
file netinet6/in6_pcb.c inet6
file netinet6/in6_prefix.c inet6
file netinet6/in6_proto.c inet6
file netinet6/in6_src.c inet6
file netinet6/ip6_forward.c inet6

View File

@ -1,4 +1,4 @@
/* $NetBSD: icmp6.h,v 1.22 2002/05/29 02:58:28 itojun Exp $ */
/* $NetBSD: icmp6.h,v 1.23 2002/06/08 21:22:30 itojun Exp $ */
/* $KAME: icmp6.h,v 1.39 2001/02/06 03:48:06 itojun Exp $ */
/*
@ -570,7 +570,9 @@ struct icmp6stat {
#define ICMPV6CTL_MTUDISC_HIWAT 16
#define ICMPV6CTL_MTUDISC_LOWAT 17
#define ICMPV6CTL_ND6_DEBUG 18
#define ICMPV6CTL_MAXID 19
#define ICMPV6CTL_ND6_DRLIST 19
#define ICMPV6CTL_ND6_PRLIST 20
#define ICMPV6CTL_MAXID 21
#define ICMPV6CTL_NAMES { \
{ 0, 0 }, \
@ -592,6 +594,8 @@ struct icmp6stat {
{ "mtudisc_hiwat", CTLTYPE_INT }, \
{ "mtudisc_lowat", CTLTYPE_INT }, \
{ "nd6_debug", CTLTYPE_INT }, \
{ 0, 0 }, \
{ 0, 0 }, \
}
#define RTF_PROBEMTU RTF_PROTO1

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6.h,v 1.40 2002/05/28 03:04:06 itojun Exp $ */
/* $NetBSD: in6.h,v 1.41 2002/06/08 21:22:31 itojun Exp $ */
/* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */
/*
@ -358,6 +358,15 @@ extern const struct in6_addr in6addr_linklocal_allrouters;
#define IN6_IS_SCOPE_LINKLOCAL(a) \
((IN6_IS_ADDR_LINKLOCAL(a)) || \
(IN6_IS_ADDR_MC_LINKLOCAL(a)))
#define IFA6_IS_DEPRECATED(a) \
((a)->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME && \
(u_int32_t)((time.tv_sec - (a)->ia6_updatetime)) > \
(a)->ia6_lifetime.ia6t_pltime)
#define IFA6_IS_INVALID(a) \
((a)->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME && \
(u_int32_t)((time.tv_sec - (a)->ia6_updatetime)) > \
(a)->ia6_lifetime.ia6t_vltime)
#endif
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_ifattach.c,v 1.47 2002/06/07 04:30:40 itojun Exp $ */
/* $NetBSD: in6_ifattach.c,v 1.48 2002/06/08 21:22:31 itojun Exp $ */
/* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.47 2002/06/07 04:30:40 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.48 2002/06/08 21:22:31 itojun Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -60,10 +60,11 @@ __KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.47 2002/06/07 04:30:40 itojun Exp
unsigned long in6_maxmtu = 0;
int ip6_auto_linklocal = 1; /* enable by default */
static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
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_addaddr __P((struct ifnet *, struct in6_ifaddr *));
static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
static int in6_ifattach_loopback __P((struct ifnet *));
@ -156,17 +157,25 @@ found:
addr = LLADDR(sdl);
addrlen = sdl->sdl_alen;
switch (ifp->if_type) {
case IFT_IEEE1394:
case IFT_IEEE80211:
/* IEEE1394 uses 16byte length address starting with EUI64 */
if (addrlen > 8)
addrlen = 8;
break;
default:
break;
}
/* get EUI64 */
switch (ifp->if_type) {
/* IEEE802/EUI64 cases - what others? */
case IFT_ETHER:
case IFT_FDDI:
case IFT_ATM:
case IFT_IEEE1394:
/* IEEE802/EUI64 cases - what others? */
/* IEEE1394 uses 16byte length address starting with EUI64 */
if (addrlen > 8)
addrlen = 8;
case IFT_IEEE80211:
/* look at IEEE802/EUI64 only */
if (addrlen != 8 && addrlen != 6)
return -1;
@ -313,191 +322,135 @@ success:
return 0;
}
/*
* configure IPv6 interface address. XXX code duplicated with in.c
*/
static int
in6_ifattach_addaddr(ifp, ia)
struct ifnet *ifp;
struct in6_ifaddr *ia;
{
struct in6_ifaddr *oia;
struct ifaddr *ifa;
int error;
int rtflag;
struct in6_addr llsol;
/*
* initialize if_addrlist, if we are the very first one
*/
ifa = TAILQ_FIRST(&ifp->if_addrlist);
if (ifa == NULL) {
TAILQ_INIT(&ifp->if_addrlist);
}
/*
* link the interface address to global list
*/
TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
IFAREF(&ia->ia_ifa);
/*
* Also link into the IPv6 address chain beginning with in6_ifaddr.
* kazu opposed it, but itojun & jinmei wanted.
*/
if ((oia = in6_ifaddr) != NULL) {
for (; oia->ia_next; oia = oia->ia_next)
continue;
oia->ia_next = ia;
} else
in6_ifaddr = ia;
IFAREF(&ia->ia_ifa);
/*
* give the interface a chance to initialize, in case this
* is the first address to be added.
*/
if (ifp->if_ioctl != NULL) {
int s;
s = splnet();
error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
splx(s);
} else
error = 0;
if (error) {
switch (error) {
case EAFNOSUPPORT:
printf("%s: IPv6 not supported\n", if_name(ifp));
break;
default:
printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
error);
break;
}
/* undo changes */
TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
IFAFREE(&ia->ia_ifa);
if (oia)
oia->ia_next = ia->ia_next;
else
in6_ifaddr = ia->ia_next;
IFAFREE(&ia->ia_ifa);
return -1;
}
/* configure link-layer address resolution */
rtflag = 0;
if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
rtflag = RTF_HOST;
else {
switch (ifp->if_type) {
case IFT_LOOP:
#ifdef IFT_STF
case IFT_STF:
#endif
rtflag = 0;
break;
default:
ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
ia->ia_ifa.ifa_flags |= RTF_CLONING;
rtflag = RTF_CLONING;
break;
}
}
/* add route to the interface. */
rtrequest(RTM_ADD,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&ia->ia_prefixmask,
RTF_UP | rtflag,
(struct rtentry **)0);
ia->ia_flags |= IFA_ROUTE;
if ((rtflag & RTF_CLONING) != 0 &&
(ifp->if_flags & IFF_MULTICAST) != 0) {
/* Restore saved multicast addresses (if any). */
in6_restoremkludge(ia, ifp);
/*
* join solicited multicast address
*/
bzero(&llsol, sizeof(llsol));
llsol.s6_addr16[0] = htons(0xff02);
llsol.s6_addr16[1] = htons(ifp->if_index);
llsol.s6_addr32[1] = 0;
llsol.s6_addr32[2] = htonl(1);
llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
llsol.s6_addr8[12] = 0xff;
if (!in6_addmulti(&llsol, ifp, &error)) {
nd6log((LOG_ERR, "%s: failed to join %s (errno=%d)\n",
if_name(ifp), ip6_sprintf(&llsol), error));
}
if (in6if_do_dad(ifp)) {
/* mark the address TENTATIVE, if needed. */
ia->ia6_flags |= IN6_IFF_TENTATIVE;
/* nd6_dad_start() will be called in in6_if_up */
}
}
return 0;
}
static int
in6_ifattach_linklocal(ifp, altifp)
struct ifnet *ifp;
struct ifnet *altifp; /*secondary EUI64 source*/
{
struct in6_ifaddr *ia;
struct in6_aliasreq ifra;
struct nd_prefix pr0;
int i, error;
/*
* configure link-local address
* configure link-local address.
*/
ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
bzero((caddr_t)ia, sizeof(*ia));
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
if (ifp->if_flags & IFF_POINTOPOINT)
ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
else
ia->ia_ifa.ifa_dstaddr = NULL;
ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
ia->ia_ifp = ifp;
bzero(&ifra, sizeof(ifra));
bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
ia->ia_prefixmask.sin6_family = AF_INET6;
ia->ia_prefixmask.sin6_addr = in6mask64;
/*
* in6_update_ifa() does not use ifra_name, but we accurately set it
* for safety.
*/
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
/* just in case */
bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
ia->ia_dstaddr.sin6_family = AF_INET6;
bzero(&ia->ia_addr, sizeof(ia->ia_addr));
ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
ia->ia_addr.sin6_family = AF_INET6;
ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
if (ifp->if_flags & IFF_LOOPBACK) {
ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
ifra.ifra_addr.sin6_family = AF_INET6;
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
} else {
if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
nd6log((LOG_ERR,
"%s: no ifid available\n", if_name(ifp)));
free(ia, M_IFADDR);
return -1;
return(-1);
}
}
ia->ia_ifa.ifa_metric = ifp->if_metric;
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
ifra.ifra_prefixmask.sin6_family = AF_INET6;
ifra.ifra_prefixmask.sin6_addr = in6mask64;
#ifdef SCOPEDROUTING
/* take into account the sin6_scope_id field for routing */
ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
#endif
/* link-local addresses should NEVER expire. */
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
if (in6_ifattach_addaddr(ifp, ia) != 0) {
/* ia will be freed on failure */
return -1;
/*
* Do not let in6_update_ifa() do DAD, since we need a random delay
* before sending an NS at the first time the interface becomes up.
* Instead, in6_if_up() will start DAD with a proper random delay.
*/
ifra.ifra_flags |= IN6_IFF_NODAD;
/*
* Now call in6_update_ifa() to do a bunch of procedures to configure
* a link-local address. We can set NULL to the 3rd argument, because
* we know there's no other link-local address on the interface
* and therefore we are adding one (instead of updating one).
*/
if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
/*
* XXX: When the interface does not support IPv6, this call
* would fail in the SIOCSIFADDR ioctl. I believe the
* notification is rather confusing in this case, so just
* suppress it. (jinmei@kame.net 20010130)
*/
if (error != EAFNOSUPPORT)
log(LOG_NOTICE, "in6_ifattach_linklocal: failed to "
"configure a link-local address on %s "
"(errno=%d)\n",
if_name(ifp), error);
return(-1);
}
/*
* Adjust ia6_flags so that in6_if_up will perform DAD.
* XXX: Some P2P interfaces seem not to send packets just after
* becoming up, so we skip p2p interfaces for safety.
*/
ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
#ifdef DIAGNOSTIC
if (!ia) {
panic("ia == NULL in in6_ifattach_linklocal");
/* NOTREACHED */
}
#endif
if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) {
ia->ia6_flags &= ~IN6_IFF_NODAD;
ia->ia6_flags |= IN6_IFF_TENTATIVE;
}
/*
* Make the link-local prefix (fe80::/64%link) as on-link.
* Since we'd like to manage prefixes separately from addresses,
* we make an ND6 prefix structure for the link-local prefix,
* and add it to the prefix list as a never-expire prefix.
* XXX: this change might affect some existing code base...
*/
bzero(&pr0, sizeof(pr0));
pr0.ndpr_ifp = ifp;
/* this should be 64 at this moment. */
pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
pr0.ndpr_prefix = ifra.ifra_addr;
/* apply the mask for safety. (nd6_prelist_add will apply it again) */
for (i = 0; i < 4; i++) {
pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
in6mask64.s6_addr32[i];
}
/*
* Initialize parameters. The link-local prefix must always be
* on-link, and its lifetimes never expire.
*/
pr0.ndpr_raf_onlink = 1;
pr0.ndpr_raf_auto = 1; /* probably meaningless */
pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
/*
* Since there is no other link-local addresses, nd6_prefix_lookup()
* probably returns NULL. However, we cannot always expect the result.
* For example, if we first remove the (only) existing link-local
* address, and then reconfigure another one, the prefix is still
* valid with referring to the old link-local address.
*/
if (nd6_prefix_lookup(&pr0) == NULL) {
if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
return(error);
}
return 0;
@ -507,52 +460,109 @@ static int
in6_ifattach_loopback(ifp)
struct ifnet *ifp; /* must be IFT_LOOP */
{
struct in6_ifaddr *ia;
struct in6_aliasreq ifra;
int error;
bzero(&ifra, sizeof(ifra));
/*
* configure link-local address
* in6_update_ifa() does not use ifra_name, but we accurately set it
* for safety.
*/
ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
bzero((caddr_t)ia, sizeof(*ia));
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
ia->ia_ifp = ifp;
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
ia->ia_prefixmask.sin6_family = AF_INET6;
ia->ia_prefixmask.sin6_addr = in6mask128;
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
ifra.ifra_prefixmask.sin6_family = AF_INET6;
ifra.ifra_prefixmask.sin6_addr = in6mask128;
/*
* Always initialize ia_dstaddr (= broadcast address) to loopback
* address, to make getifaddr happier.
*
* For BSDI, it is mandatory. The BSDI version of
* ifa_ifwithroute() rejects to add a route to the loopback
* interface. Even for other systems, loopback looks somewhat
* special.
* address. Follows IPv4 practice - see in_ifinit().
*/
bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
ia->ia_dstaddr.sin6_family = AF_INET6;
ia->ia_dstaddr.sin6_addr = in6addr_loopback;
ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
ifra.ifra_dstaddr.sin6_family = AF_INET6;
ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
bzero(&ia->ia_addr, sizeof(ia->ia_addr));
ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
ia->ia_addr.sin6_family = AF_INET6;
ia->ia_addr.sin6_addr = in6addr_loopback;
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
ifra.ifra_addr.sin6_family = AF_INET6;
ifra.ifra_addr.sin6_addr = in6addr_loopback;
ia->ia_ifa.ifa_metric = ifp->if_metric;
/* the loopback address should NEVER expire. */
ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
if (in6_ifattach_addaddr(ifp, ia) != 0) {
/* ia will be freed on failure */
return -1;
/* we don't need to perform DAD on loopback interfaces. */
ifra.ifra_flags |= IN6_IFF_NODAD;
/*
* We are sure that this is a newly assigned address, so we can set
* NULL to the 3rd arg.
*/
if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
log(LOG_ERR, "in6_ifattach_loopback: failed to configure "
"the loopback address on %s (errno=%d)\n",
if_name(ifp), error);
return(-1);
}
return 0;
}
/*
* compute NI group address, based on the current hostname setting.
* see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
*
* when ifp == NULL, the caller is responsible for filling scopeid.
*/
int
in6_nigroup(ifp, name, namelen, sa6)
struct ifnet *ifp;
const char *name;
int namelen;
struct sockaddr_in6 *sa6;
{
const char *p;
u_char *q;
MD5_CTX ctxt;
u_int8_t digest[16];
char l;
char n[64]; /* a single label must not exceed 63 chars */
if (!namelen || !name)
return -1;
p = name;
while (p && *p && *p != '.' && p - name < namelen)
p++;
if (p - name > sizeof(n) - 1)
return -1; /* label too long */
l = p - name;
strncpy(n, name, l);
n[(int)l] = '\0';
for (q = n; *q; q++) {
if ('A' <= *q && *q <= 'Z')
*q = *q - 'A' + 'a';
}
/* generate 8 bytes of pseudo-random value. */
bzero(&ctxt, sizeof(ctxt));
MD5Init(&ctxt);
MD5Update(&ctxt, &l, sizeof(l));
MD5Update(&ctxt, n, l);
MD5Final(digest, &ctxt);
bzero(sa6, sizeof(*sa6));
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(*sa6);
sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
sa6->sin6_addr.s6_addr8[11] = 2;
bcopy(digest, &sa6->sin6_addr.s6_addr32[3],
sizeof(sa6->sin6_addr.s6_addr32[3]));
return 0;
}
/*
* XXX multiple loopback interface needs more care. for instance,
* nodelocal address needs to be configured onto only one of them.
@ -563,10 +573,6 @@ in6_ifattach(ifp, altifp)
struct ifnet *ifp;
struct ifnet *altifp; /* secondary EUI64 source */
{
struct sockaddr_in6 mltaddr;
struct sockaddr_in6 mltmask;
struct sockaddr_in6 gate;
struct sockaddr_in6 mask;
struct in6_ifaddr *ia;
struct in6_addr in6;
@ -616,125 +622,27 @@ in6_ifattach(ifp, altifp)
}
/*
* assign link-local address, if there's none
*/
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL) {
if (in6_ifattach_linklocal(ifp, altifp) != 0)
return;
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL) {
printf("%s: failed to add link-local address\n",
if_name(ifp));
/* we can't initialize multicasts without link-local */
return;
}
}
if (ifp->if_flags & IFF_POINTOPOINT) {
/*
* route local address to loopback
*/
bzero(&gate, sizeof(gate));
gate.sin6_len = sizeof(struct sockaddr_in6);
gate.sin6_family = AF_INET6;
gate.sin6_addr = in6addr_loopback;
bzero(&mask, sizeof(mask));
mask.sin6_len = sizeof(struct sockaddr_in6);
mask.sin6_family = AF_INET6;
mask.sin6_addr = in6mask64;
rtrequest(RTM_ADD,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&gate,
(struct sockaddr *)&mask,
RTF_UP|RTF_HOST,
(struct rtentry **)0);
}
/*
* assign loopback address for loopback interface
* XXX multiple loopback interface case
* assign loopback address for loopback interface.
* XXX multiple loopback interface case.
*/
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
in6 = in6addr_loopback;
if (ifp->if_flags & IFF_LOOPBACK) {
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
if (in6_ifattach_loopback(ifp) != 0)
return;
}
}
#ifdef DIAGNOSTIC
if (!ia) {
panic("ia == NULL in in6_ifattach");
/*NOTREACHED*/
}
#endif
/*
* join multicast
* assign a link-local address, if there's none.
*/
if (ifp->if_flags & IFF_MULTICAST) {
int error; /* not used */
struct in6_multi *in6m;
/* Restore saved multicast addresses (if any). */
in6_restoremkludge(ia, ifp);
bzero(&mltmask, sizeof(mltmask));
mltmask.sin6_len = sizeof(struct sockaddr_in6);
mltmask.sin6_family = AF_INET6;
mltmask.sin6_addr = in6mask32;
/*
* join link-local all-nodes address
*/
bzero(&mltaddr, sizeof(mltaddr));
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
mltaddr.sin6_family = AF_INET6;
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
if (in6m == NULL) {
rtrequest(RTM_ADD,
(struct sockaddr *)&mltaddr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask,
RTF_UP|RTF_CLONING, /* xxx */
(struct rtentry **)0);
if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
nd6log((LOG_ERR, "%s: failed to join %s "
"(errno=%d)\n", if_name(ifp),
ip6_sprintf(&mltaddr.sin6_addr),
error));
}
}
if (ifp->if_flags & IFF_LOOPBACK) {
in6 = in6addr_loopback;
ia = in6ifa_ifpwithaddr(ifp, &in6);
/*
* join node-local all-nodes address, on loopback
*/
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
if (in6m == NULL && ia != NULL) {
rtrequest(RTM_ADD,
(struct sockaddr *)&mltaddr,
(struct sockaddr *)&ia->ia_addr,
(struct sockaddr *)&mltmask,
RTF_UP,
(struct rtentry **)0);
if (!in6_addmulti(&mltaddr.sin6_addr, ifp,
&error)) {
nd6log((LOG_ERR, "%s: failed to join "
"%s (errno=%d)\n", if_name(ifp),
ip6_sprintf(&mltaddr.sin6_addr),
error));
}
if (ip6_auto_linklocal) {
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL) {
if (in6_ifattach_linklocal(ifp, altifp) == 0) {
/* linklocal address assigned */
} else {
/* failed to assign linklocal address. bark? */
}
}
}
@ -754,9 +662,7 @@ in6_ifdetach(ifp)
struct rtentry *rt;
short rtflags;
struct sockaddr_in6 sin6;
/* nuke prefix list. this may try to remove some of ifaddrs as well */
in6_purgeprefix(ifp);
struct in6_multi_mship *imm;
/* remove neighbor management table */
nd6_purge(ifp);
@ -767,7 +673,7 @@ in6_ifdetach(ifp)
next = ifa->ifa_list.tqe_next;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
in6_purgeaddr(ifa, ifp);
in6_purgeaddr(ifa);
}
/* undo everything done by in6_ifattach(), just in case */
@ -783,9 +689,17 @@ in6_ifdetach(ifp)
ia = (struct in6_ifaddr *)ifa;
/*
* leave from multicast groups we have joined for the interface
*/
while ((imm = ia->ia6_memberships.lh_first) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
in6_leavegroup(imm);
}
/* remove from the routing table */
if ((ia->ia_flags & IFA_ROUTE)
&& (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
if ((ia->ia_flags & IFA_ROUTE) &&
(rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
rtflags = rt->rt_flags;
rtfree(rt);
rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_ifattach.h,v 1.7 2001/10/16 04:57:38 itojun Exp $ */
/* $NetBSD: in6_ifattach.h,v 1.8 2002/06/08 21:22:31 itojun Exp $ */
/* $KAME: in6_ifattach.h,v 1.8 2000/04/12 03:51:30 itojun Exp $ */
/*
@ -36,6 +36,7 @@
#ifdef _KERNEL
void in6_ifattach __P((struct ifnet *, struct ifnet *));
void in6_ifdetach __P((struct ifnet *));
int in6_nigroup(struct ifnet *, const char *, int, struct sockaddr_in6 *);
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_IFATTACH_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_pcb.h,v 1.19 2001/10/24 06:36:38 itojun Exp $ */
/* $NetBSD: in6_pcb.h,v 1.20 2002/06/08 21:22:31 itojun Exp $ */
/* $KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $ */
/*
@ -176,11 +176,6 @@ void in6_setpeeraddr __P((struct in6pcb *, struct mbuf *));
void in6_setsockaddr __P((struct in6pcb *, struct mbuf *));
/* in in6_src.c */
struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *,
struct ip6_pktopts *,
struct ip6_moptions *,
struct route_in6 *,
struct in6_addr *, int *));
int in6_selecthlim __P((struct in6pcb *, struct ifnet *));
int in6_pcbsetport __P((struct in6_addr *, struct in6pcb *));

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +0,0 @@
/* $NetBSD: in6_prefix.h,v 1.5 2001/02/10 04:14:27 itojun Exp $ */
/* $KAME: in6_prefix.h,v 1.10 2001/02/08 16:30:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/callout.h>
struct rr_prefix {
struct ifprefix rp_ifpr;
LIST_ENTRY(rr_prefix) rp_entry;
LIST_HEAD(rp_addrhead, rp_addr) rp_addrhead;
struct sockaddr_in6 rp_prefix; /* prefix */
u_int32_t rp_vltime; /* advertised valid lifetime */
u_int32_t rp_pltime; /* advertised preferred lifetime */
time_t rp_expire; /* expiration time of the prefix */
time_t rp_preferred; /* preferred time of the prefix */
struct in6_prflags rp_flags;
u_char rp_origin; /* from where this prefix info is obtained */
struct rp_stateflags {
/* if some prefix should be added to this prefix */
u_char addmark : 1;
u_char delmark : 1; /* if this prefix will be deleted */
} rp_stateflags;
};
#define rp_type rp_ifpr.ifpr_type
#define rp_ifp rp_ifpr.ifpr_ifp
#define rp_plen rp_ifpr.ifpr_plen
#define rp_raf rp_flags.prf_ra
#define rp_raf_onlink rp_flags.prf_ra.onlink
#define rp_raf_auto rp_flags.prf_ra.autonomous
#define rp_statef_addmark rp_stateflags.addmark
#define rp_statef_delmark rp_stateflags.delmark
#define rp_rrf rp_flags.prf_rr
#define rp_rrf_decrvalid rp_flags.prf_rr.decrvalid
#define rp_rrf_decrprefd rp_flags.prf_rr.decrprefd
struct rp_addr {
LIST_ENTRY(rp_addr) ra_entry;
struct in6_addr ra_ifid;
struct in6_ifaddr *ra_addr;
struct ra_flags {
u_char anycast : 1;
} ra_flags;
};
#define ifpr2rp(ifpr) ((struct rr_prefix *)(ifpr))
#define rp2ifpr(rp) ((struct ifprefix *)(rp))
#define RP_IN6(rp) (&(rp)->rp_prefix.sin6_addr)
#define RR_INFINITE_LIFETIME 0xffffffff
LIST_HEAD(rr_prhead, rr_prefix);
extern struct rr_prhead rr_prefix;
void in6_rr_timer __P((void *));
extern struct callout in6_rr_timer_ch;
int delete_each_prefix __P((struct rr_prefix *rpp, u_char origin));

View File

@ -1,5 +1,5 @@
/* $NetBSD: in6_var.h,v 1.31 2002/06/08 00:07:00 itojun Exp $ */
/* $KAME: in6_var.h,v 1.53 2001/02/10 02:44:27 itojun Exp $ */
/* $NetBSD: in6_var.h,v 1.32 2002/06/08 21:22:32 itojun Exp $ */
/* $KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -111,8 +111,17 @@ struct in6_ifaddr {
/* list of multicast addresses */
int ia6_flags;
struct in6_addrlifetime ia6_lifetime; /* NULL = infty */
struct ifprefix *ia6_ifpr; /* back pointer to ifprefix */
struct in6_addrlifetime ia6_lifetime;
time_t ia6_createtime; /* the creation time of this address, which is
* currently used for temporary addresses only.
*/
time_t ia6_updatetime;
/* back pointer to the ND prefix (for autoconfigured addresses only) */
struct nd_prefix *ia6_ndpr;
/* multicast addresses joined from the kernel */
LIST_HEAD(, in6_multi_mship) ia6_memberships;
};
/*
@ -270,7 +279,8 @@ struct in6_prflags {
struct prf_ra {
u_char onlink : 1;
u_char autonomous : 1;
u_char reserved : 6;
u_char router : 1;
u_char reserved : 5;
} prf_ra;
u_char prf_reserved1;
u_short prf_reserved2;
@ -352,8 +362,6 @@ struct in6_rrenumreq {
#define IFA_IN6(x) (&((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr)
#define IFA_DSTIN6(x) (&((struct sockaddr_in6 *)((x)->ifa_dstaddr))->sin6_addr)
#define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr)
#ifdef _KERNEL
#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
(((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
@ -387,7 +395,7 @@ struct in6_rrenumreq {
#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq)
#define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist)
#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_prlist)
#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_oprlist)
#ifdef _KERNEL
#define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq)
#endif
@ -426,6 +434,10 @@ struct in6_rrenumreq {
#define IN6_IFF_DUPLICATED 0x04 /* DAD detected duplicate */
#define IN6_IFF_DETACHED 0x08 /* may be detached from the link */
#define IN6_IFF_DEPRECATED 0x10 /* deprecated address */
#define IN6_IFF_NODAD 0x20 /* don't perform DAD on this address
* (used only at first SIOC* call)
*/
#define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */
/* do not input/output */
#define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)
@ -564,12 +576,13 @@ void in6_delmulti __P((struct in6_multi *));
struct in6_multi_mship *in6_joingroup __P((struct ifnet *, struct in6_addr *,
int *));
int in6_leavegroup __P((struct in6_multi_mship *));
void in6_ifscrub __P((struct ifnet *, struct in6_ifaddr *));
int in6_ifindex2scopeid __P((int));
int in6_mask2len __P((struct in6_addr *));
int in6_mask2len __P((struct in6_addr *, u_char *));
int in6_control __P((struct socket *, u_long, caddr_t, struct ifnet *,
struct proc *));
void in6_purgeaddr __P((struct ifaddr *, struct ifnet *));
int in6_update_ifa __P((struct ifnet *, struct in6_aliasreq *,
struct in6_ifaddr *));
void in6_purgeaddr __P((struct ifaddr *));
int in6if_do_dad __P((struct ifnet *));
void in6_purgeif __P((struct ifnet *));
void in6_savemkludge __P((struct in6_ifaddr *));
@ -586,12 +599,9 @@ int in6_addr2scopeid __P((struct ifnet *, struct in6_addr *));
int in6_matchlen __P((struct in6_addr *, struct in6_addr *));
int in6_are_prefix_equal __P((struct in6_addr *, struct in6_addr *, int));
void in6_prefixlen2mask __P((struct in6_addr *, int));
int in6_prefix_ioctl __P((struct socket *so, u_long cmd, caddr_t data,
struct ifnet *ifp));
int in6_prefix_add_ifid __P((int, struct in6_ifaddr *));
void in6_prefix_remove_ifid __P((int, struct in6_ifaddr *));
void in6_purgeprefix __P((struct ifnet *));
int in6_is_addr_deprecated __P((struct sockaddr_in6 *));
struct in6pcb;
int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *,
struct in6pcb *, struct ifnet **));

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_forward.c,v 1.30 2002/06/07 04:18:12 itojun Exp $ */
/* $NetBSD: ip6_forward.c,v 1.31 2002/06/08 21:22:33 itojun Exp $ */
/* $KAME: ip6_forward.c,v 1.74 2001/06/12 23:54:55 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.30 2002/06/07 04:18:12 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.31 2002/06/08 21:22:33 itojun Exp $");
#include "opt_ipsec.h"
#include "opt_pfil_hooks.h"
@ -528,12 +528,10 @@ ip6_forward(m, srcrt)
return;
switch (error) {
case 0:
#if 1
if (type == ND_REDIRECT) {
icmp6_redirect_output(mcopy, rt);
return;
}
#endif
goto freecopy;
case EMSGSIZE:

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_input.c,v 1.54 2002/05/28 10:11:51 itojun Exp $ */
/* $NetBSD: ip6_input.c,v 1.55 2002/06/08 21:22:33 itojun Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.54 2002/05/28 10:11:51 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.55 2002/06/08 21:22:33 itojun Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -109,7 +109,6 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.54 2002/05/28 10:11:51 itojun Exp $"
#include <netinet/icmp6.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/nd6.h>
#include <netinet6/in6_prefix.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
@ -193,18 +192,10 @@ static void
ip6_init2(dummy)
void *dummy;
{
/*
* to route local address of p2p link to loopback,
* assign loopback address first.
*/
in6_ifattach(&loif[0], NULL);
/* nd6_timer_init */
callout_init(&nd6_timer_ch);
callout_reset(&nd6_timer_ch, hz, nd6_timer, NULL);
/* router renumbering prefix list maintenance */
callout_init(&in6_rr_timer_ch);
callout_reset(&in6_rr_timer_ch, hz, in6_rr_timer, NULL);
}
/*
@ -281,7 +272,7 @@ ip6_input(m)
if (m->m_len < sizeof(struct ip6_hdr)) {
struct ifnet *inifp;
inifp = m->m_pkthdr.rcvif;
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) {
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
ip6stat.ip6s_toosmall++;
in6_ifstat_inc(inifp, ifs6_in_hdrerr);
return;
@ -337,6 +328,9 @@ ip6_input(m)
*/
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) ||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {
/*
* XXX: "badscope" is not very suitable for a multicast source.
*/
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
@ -497,6 +491,7 @@ ip6_input(m)
if (ip6_forward_rt.ro_rt &&
(ip6_forward_rt.ro_rt->rt_flags &
(RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&
!(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) &&
#if 0
/*
* The check below is redundant since the comparison of
@ -532,7 +527,7 @@ ip6_input(m)
}
/*
* FAITH(Firewall Aided Internet Translator)
* FAITH (Firewall Aided Internet Translator)
*/
#if defined(NFAITH) && 0 < NFAITH
if (ip6_keepfaith) {
@ -812,6 +807,10 @@ ip6_hopopts_input(plenp, rtalertp, mp, offp)
* This function is separate from ip6_hopopts_input() in order to
* handle a case where the sending node itself process its hop-by-hop
* options header. In such a case, the function is called from ip6_output().
*
* The function assumes that hbh header is located right after the IPv6 header
* (RFC2460 p7), opthead is pointer into data content in m, and opthead to
* opthead + hbhlen is located in continuous memory region.
*/
int
ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
@ -826,6 +825,7 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
u_int8_t *opt = opthead;
u_int16_t rtalert_val;
u_int32_t jumboplen;
const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh);
for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) {
switch (*opt) {
@ -846,9 +846,11 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
goto bad;
}
if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) {
/* XXX: should we discard the packet? */
log(LOG_ERR, "length of router alert opt is inconsitent(%d)",
*(opt + 1));
/* XXX stat */
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
erroff + opt + 1 - opthead);
return (-1);
}
optlen = IP6OPT_RTALERT_LEN;
bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2);
@ -861,10 +863,11 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
goto bad;
}
if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) {
/* XXX: should we discard the packet? */
log(LOG_ERR, "length of jumbopayload opt "
"is inconsistent(%d)\n",
*(opt + 1));
/* XXX stat */
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
erroff + opt + 1 - opthead);
return (-1);
}
optlen = IP6OPT_JUMBO_LEN;
@ -877,10 +880,8 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
ip6stat.ip6s_badoptions++;
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
sizeof(struct ip6_hdr) +
sizeof(struct ip6_hbh) +
opt - opthead);
return(-1);
erroff + opt - opthead);
return (-1);
}
/*
@ -903,10 +904,8 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
ip6stat.ip6s_badoptions++;
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
sizeof(struct ip6_hdr) +
sizeof(struct ip6_hbh) +
opt + 2 - opthead);
return(-1);
erroff + opt + 2 - opthead);
return (-1);
}
#endif
@ -917,10 +916,8 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
ip6stat.ip6s_badoptions++;
icmp6_error(m, ICMP6_PARAM_PROB,
ICMP6_PARAMPROB_HEADER,
sizeof(struct ip6_hdr) +
sizeof(struct ip6_hbh) +
opt + 2 - opthead);
return(-1);
erroff + opt + 2 - opthead);
return (-1);
}
*plenp = jumboplen;
@ -930,21 +927,20 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
ip6stat.ip6s_toosmall++;
goto bad;
}
if ((optlen = ip6_unknown_opt(opt, m,
sizeof(struct ip6_hdr) +
sizeof(struct ip6_hbh) +
opt - opthead)) == -1)
return(-1);
optlen = ip6_unknown_opt(opt, m,
erroff + opt - opthead);
if (optlen == -1)
return (-1);
optlen += 2;
break;
}
}
return(0);
return (0);
bad:
m_freem(m);
return(-1);
return (-1);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_output.c,v 1.53 2002/06/07 22:03:02 itojun Exp $ */
/* $NetBSD: ip6_output.c,v 1.54 2002/06/08 21:22:33 itojun Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.53 2002/06/07 22:03:02 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.54 2002/06/08 21:22:33 itojun Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -433,7 +433,7 @@ skip_ipsec2:;
/* Source address validation */
if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) &&
(flags & IPV6_DADOUTPUT) == 0) {
(flags & IPV6_UNSPECSRC) == 0) {
error = EOPNOTSUPP;
ip6stat.ip6s_badscope++;
goto bad;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_var.h,v 1.20 2002/06/07 22:03:02 itojun Exp $ */
/* $NetBSD: ip6_var.h,v 1.21 2002/06/08 21:22:33 itojun Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@ -107,7 +107,7 @@ struct ip6asfrag {
u_int16_t ip6af_mff; /* more fragment bit in frag off */
};
#define IP6_REASS_MBUF(ip6af) (*(struct mbuf **)&((ip6af)->ip6af_m))
#define IP6_REASS_MBUF(ip6af) ((ip6af)->ip6af_m)
struct ip6_moptions {
struct ifnet *im6o_multicast_ifp; /* ifp for outgoing multicasts */
@ -202,7 +202,7 @@ struct ip6stat {
#ifdef _KERNEL
/* flags passed to ip6_output as last parameter */
#define IPV6_DADOUTPUT 0x01 /* DAD */
#define IPV6_UNSPECSRC 0x01 /* allow :: as the source address */
#define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */
#define IPV6_MINMTU 0x04 /* use minimum MTU (IPV6_USE_MIN_MTU) */
@ -232,6 +232,7 @@ extern int ip6_dad_count; /* DupAddrDetectionTransmits */
extern u_int32_t ip6_flow_seq;
extern int ip6_auto_flowlabel;
extern int ip6_auto_linklocal;
extern int ip6_anonportmin; /* minimum ephemeral port */
extern int ip6_anonportmax; /* maximum ephemeral port */
@ -285,6 +286,10 @@ int rip6_usrreq __P((struct socket *,
int dest6_input __P((struct mbuf **, int *, int));
int none_input __P((struct mbuf **, int *, int));
struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *,
struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *,
struct in6_addr *, int *));
#endif /* _KERNEL */
#endif /* !_NETINET6_IP6_VAR_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: mld6.c,v 1.18 2002/01/08 04:37:32 itojun Exp $ */
/* $NetBSD: mld6.c,v 1.19 2002/06/08 21:22:34 itojun Exp $ */
/* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */
/*
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.18 2002/01/08 04:37:32 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.19 2002/06/08 21:22:34 itojun Exp $");
#include "opt_inet.h"
@ -157,8 +157,9 @@ mld6_start_listening(in6m)
in6m->in6m_state = MLD6_OTHERLISTENER;
} else {
mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, NULL);
in6m->in6m_timer = MLD6_RANDOM_DELAY(
MLD6_UNSOLICITED_REPORT_INTERVAL * PR_FASTHZ);
in6m->in6m_timer =
MLD6_RANDOM_DELAY(MLD6_UNSOLICITED_REPORT_INTERVAL *
PR_FASTHZ);
in6m->in6m_state = MLD6_IREPORTEDLAST;
mld6_timers_are_running = 1;
}
@ -339,6 +340,11 @@ mld6_input(m, off)
break;
default: /* this is impossible */
#if 0
/*
* this case should be impossible because of filtering in
* icmp6_input(). But we explicitly disabled this part
* just in case.
*/
log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type);
#endif
break;
@ -353,7 +359,6 @@ mld6_fasttimeo()
struct in6_multi *in6m;
struct in6_multistep step;
int s;
/*
* Quick check to see if any work needs to be done, in order
* to minimize the overhead of fasttimo processing.
@ -390,14 +395,19 @@ mld6_sendpkt(in6m, type, dst)
struct ip6_moptions im6o;
struct in6_ifaddr *ia;
struct ifnet *ifp = in6m->in6m_ifp;
int ignflags;
/*
* At first, find a link local address on the outgoing interface
* to use as the source address of the MLD packet.
* We do not reject tentative addresses for MLD report to deal with
* the case where we first join a link-local address.
*/
if ((ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST))
== NULL)
ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE;
if ((ia = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL)
return;
if ((ia->ia6_flags & IN6_IFF_TENTATIVE))
ia = NULL;
/*
* Allocate mbufs to store ip6 header and MLD header.
@ -414,6 +424,7 @@ mld6_sendpkt(in6m, type, dst)
}
mh->m_next = md;
mh->m_pkthdr.rcvif = NULL;
mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr);
mh->m_len = sizeof(struct ip6_hdr);
MH_ALIGN(mh, sizeof(struct ip6_hdr));
@ -426,7 +437,7 @@ mld6_sendpkt(in6m, type, dst)
/* ip6_plen will be set later */
ip6->ip6_nxt = IPPROTO_ICMPV6;
/* ip6_hlim will be set by im6o.im6o_multicast_hlim */
ip6->ip6_src = ia->ia_addr.sin6_addr;
ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
/* fill in the MLD header */
@ -458,8 +469,6 @@ mld6_sendpkt(in6m, type, dst)
/* increment output statictics */
icmp6stat.icp6s_outhist[type]++;
ip6_output(mh, &ip6_opts, NULL, 0, &im6o, NULL);
icmp6_ifstat_inc(ifp, ifs6_out_msg);
switch (type) {
case MLD6_LISTENER_QUERY:
@ -472,4 +481,6 @@ mld6_sendpkt(in6m, type, dst)
icmp6_ifstat_inc(ifp, ifs6_out_mlddone);
break;
}
ip6_output(mh, &ip6_opts, NULL, ia ? 0 : IPV6_UNSPECSRC, &im6o, NULL);
}

View File

@ -1,5 +1,5 @@
/* $NetBSD: nd6.c,v 1.64 2002/06/07 17:15:12 itojun Exp $ */
/* $KAME: nd6.c,v 1.151 2001/06/19 14:24:41 sumikawa Exp $ */
/* $NetBSD: nd6.c,v 1.65 2002/06/08 21:22:34 itojun Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.64 2002/06/07 17:15:12 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.65 2002/06/08 21:22:34 itojun Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -61,7 +61,6 @@ __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.64 2002/06/07 17:15:12 itojun Exp $");
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/in6_prefix.h>
#include <netinet/icmp6.h>
#include "loop.h"
@ -111,6 +110,9 @@ static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int));
struct callout nd6_slowtimo_ch;
struct callout nd6_timer_ch;
static int fill_drlist __P((void *, size_t *, size_t));
static int fill_prlist __P((void *, size_t *, size_t));
void
nd6_init()
{
@ -152,7 +154,12 @@ nd6_ifattach(ifp)
nd->basereachable = REACHABLE_TIME;
nd->reachable = ND_COMPUTE_RTIME(nd->basereachable);
nd->retrans = RETRANS_TIMER;
nd->flags = ND6_IFF_PERFORMNUD;
/*
* Note that the default value of ip6_accept_rtadv is 0, which means
* we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV
* here.
*/
nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
nd6_setmtu0(ifp, nd);
@ -374,6 +381,9 @@ nd6_timer(ignored_arg)
struct nd_defrouter *dr;
struct nd_prefix *pr;
long time_second = time.tv_sec;
struct ifnet *ifp;
struct in6_ifaddr *ia6, *nia6;
struct in6_addrlifetime *lt6;
s = splsoftnet();
callout_reset(&nd6_timer_ch, nd6_prune * hz,
@ -382,7 +392,6 @@ nd6_timer(ignored_arg)
ln = llinfo_nd6.ln_next;
while (ln && ln != &llinfo_nd6) {
struct rtentry *rt;
struct ifnet *ifp;
struct sockaddr_in6 *dst;
struct llinfo_nd6 *next = ln->ln_next;
/* XXX: used for the DELAY case only: */
@ -424,16 +433,15 @@ nd6_timer(ignored_arg)
} else {
struct mbuf *m = ln->ln_hold;
if (m) {
if (rt->rt_ifp) {
/*
* Fake rcvif to make ICMP error
* more helpful in diagnosing
* for the receiver.
* Fake rcvif to make the ICMP error
* more helpful in diagnosing for the
* receiver.
* XXX: should we consider
* older rcvif?
*/
m->m_pkthdr.rcvif = rt->rt_ifp;
}
icmp6_error(m, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADDR, 0);
ln->ln_hold = NULL;
@ -462,8 +470,7 @@ nd6_timer(ignored_arg)
ln->ln_expire = time_second +
ND6_RETRANS_SEC(ndi->retrans);
nd6_ns_output(ifp, &dst->sin6_addr,
&dst->sin6_addr,
ln, 0);
&dst->sin6_addr, ln, 0);
} else {
ln->ln_state = ND6_LLINFO_STALE; /* XXX */
ln->ln_expire = time_second + nd6_gctimer;
@ -496,46 +503,47 @@ nd6_timer(ignored_arg)
dr = TAILQ_NEXT(dr, dr_entry);
}
}
pr = nd_prefix.lh_first;
while (pr) {
struct in6_ifaddr *ia6;
struct in6_addrlifetime *lt6;
if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
ia6 = NULL;
else
ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
if (ia6) {
/*
* expire interface addresses.
* in the past the loop was inside prefix expiry processing.
* However, from a stricter speci-confrmance standpoint, we should
* rather separate address lifetimes and prefix lifetimes.
*/
for (ia6 = in6_ifaddr; ia6; ia6 = nia6) {
nia6 = ia6->ia_next;
/* check address lifetime */
lt6 = &ia6->ia6_lifetime;
if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second)
if (IFA6_IS_INVALID(ia6)) {
in6_purgeaddr(&ia6->ia_ifa);
}
if (IFA6_IS_DEPRECATED(ia6)) {
ia6->ia6_flags |= IN6_IFF_DEPRECATED;
if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) {
if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
/* xxx ND_OPT_PI_FLAG_ONLINK processing */
} else {
/*
* A new RA might have made a deprecated address
* preferred.
*/
ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
}
}
/* expire prefix list */
pr = nd_prefix.lh_first;
while (pr) {
/*
* check prefix lifetime.
* since pltime is just for autoconf, pltime processing for
* prefix is not necessary.
*
* we offset expire time by NDPR_KEEP_EXPIRE, so that we
* can use the old prefix information to validate the
* next prefix information to come. See prelist_update()
* for actual validation.
*/
if (pr->ndpr_expire
&& pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) {
if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&
time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) {
struct nd_prefix *t;
t = pr->ndpr_next;
/*
* address expiration and prefix expiration are
* separate. NEVER perform in6_ifdel here.
* separate. NEVER perform in6_purgeaddr here.
*/
prelist_remove(pr);
@ -555,21 +563,28 @@ nd6_purge(ifp)
struct ifnet *ifp;
{
struct llinfo_nd6 *ln, *nln;
struct nd_defrouter *dr, *ndr, drany;
struct nd_defrouter *dr, *ndr;
struct nd_prefix *pr, *npr;
/* Nuke default router list entries toward ifp */
if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) {
/*
* The first entry of the list may be stored in
* the routing table, so we'll delete it later.
* Nuke default router list entries toward ifp.
* We defer removal of default router list entries that is installed
* in the routing table, in order to keep additional side effects as
* small as possible.
*/
for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) {
for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {
ndr = TAILQ_NEXT(dr, dr_entry);
if (dr->installed)
continue;
if (dr->ifp == ifp)
defrtrlist_del(dr);
}
dr = TAILQ_FIRST(&nd_defrouter);
for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {
ndr = TAILQ_NEXT(dr, dr_entry);
if (!dr->installed)
continue;
if (dr->ifp == ifp)
defrtrlist_del(dr);
}
@ -578,8 +593,14 @@ nd6_purge(ifp)
for (pr = nd_prefix.lh_first; pr; pr = npr) {
npr = pr->ndpr_next;
if (pr->ndpr_ifp == ifp) {
if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
/*
* Previously, pr->ndpr_addr is removed as well,
* but I strongly believe we don't have to do it.
* nd6_purge() is only called from in6_ifdetach(),
* which removes all the associated interface addresses
* by itself.
* (jinmei@kame.net 20010129)
*/
prelist_remove(pr);
}
}
@ -590,8 +611,6 @@ nd6_purge(ifp)
if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */
/* refresh default router list */
bzero(&drany, sizeof(drany));
defrouter_delreq(&drany, 0);
defrouter_select();
}
@ -667,12 +686,9 @@ nd6_lookup(addr6, create, ifp)
* called in rtrequest via ifa->ifa_rtrequest.
*/
if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
ifa->ifa_addr,
(struct sockaddr *)&all1_sa,
(ifa->ifa_flags |
RTF_HOST | RTF_LLINFO) &
~RTF_CLONING,
&rt)) != 0) {
ifa->ifa_addr, (struct sockaddr *)&all1_sa,
(ifa->ifa_flags | RTF_HOST | RTF_LLINFO) &
~RTF_CLONING, &rt)) != 0) {
#if 0
log(LOG_ERR,
"nd6_lookup: failed to add route for a "
@ -694,19 +710,26 @@ nd6_lookup(addr6, create, ifp)
rt->rt_refcnt--;
/*
* Validation for the entry.
* Note that the check for rt_llinfo is necessary because a cloned
* route from a parent route that has the L flag (e.g. the default
* route to a p2p interface) may have the flag, too, while the
* destination is not actually a neighbor.
* XXX: we can't use rt->rt_ifp to check for the interface, since
* it might be the loopback interface if the entry is for our
* own address on a non-loopback interface. Instead, we should
* use rt->rt_ifa->ifa_ifp, which would specify the REAL interface.
* use rt->rt_ifa->ifa_ifp, which would specify the REAL
* interface.
*/
if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
rt->rt_gateway->sa_family != AF_LINK ||
rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL ||
(ifp && rt->rt_ifa->ifa_ifp != ifp)) {
if (create) {
log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n",
ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec");
log(LOG_DEBUG,
"nd6_lookup: failed to lookup %s (if = %s)\n",
ip6_sprintf(addr6),
ifp ? if_name(ifp) : "unspec");
}
return(0);
return(NULL);
}
return(rt);
}
@ -720,11 +743,8 @@ nd6_is_addr_neighbor(addr, ifp)
struct sockaddr_in6 *addr;
struct ifnet *ifp;
{
struct ifaddr *ifa;
int i;
#define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr)
#define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr)
struct nd_prefix *pr;
struct rtentry *rt;
/*
* A link-local address is always a neighbor.
@ -737,22 +757,29 @@ nd6_is_addr_neighbor(addr, ifp)
return(1);
/*
* If the address matches one of our addresses,
* it should be a neighbor.
* If the address matches one of our on-link prefixes, it should be a
* neighbor.
*/
for (ifa = ifp->if_addrlist.tqh_first;
ifa;
ifa = ifa->ifa_list.tqe_next)
{
if (ifa->ifa_addr->sa_family != AF_INET6)
next: continue;
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
if (pr->ndpr_ifp != ifp)
continue;
for (i = 0; i < 4; i++) {
if ((IFADDR6(ifa).s6_addr32[i] ^
addr->sin6_addr.s6_addr32[i]) &
IFMASK6(ifa).s6_addr32[i])
goto next;
if (!(pr->ndpr_stateflags & NDPRF_ONLINK))
continue;
if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
&addr->sin6_addr, &pr->ndpr_mask))
return (1);
}
/*
* If the default router list is empty, all addresses are regarded
* as on-link, and thus, as a neighbor.
* XXX: we restrict the condition to hosts, because routers usually do
* not have the "default router list".
*/
if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL &&
nd6_defifindex == ifp->if_index) {
return(1);
}
@ -760,12 +787,10 @@ nd6_is_addr_neighbor(addr, ifp)
* Even if the address matches none of our addresses, it might be
* in the neighbor cache.
*/
if (nd6_lookup(&addr->sin6_addr, 0, ifp))
if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL)
return(1);
return(0);
#undef IFADDR6
#undef IFMASK6
}
/*
@ -846,20 +871,11 @@ nd6_free(rt, gc)
*/
pfxlist_onlink_check();
if (dr == TAILQ_FIRST(&nd_defrouter)) {
/*
* It is used as the current default router,
* so we have to move it to the end of the
* list and choose a new one.
* XXX: it is not very efficient if this is
* the only router.
* refresh default router list
*/
TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry);
defrouter_select();
}
}
splx(s);
}
@ -946,8 +962,9 @@ nd6_rtrequest(req, rt, info)
struct ifnet *ifp = rt->rt_ifp;
struct ifaddr *ifa;
long time_second = time.tv_sec;
int mine = 0;
if ((rt->rt_flags & RTF_GATEWAY))
if ((rt->rt_flags & RTF_GATEWAY) != 0)
return;
if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) {
@ -961,6 +978,27 @@ nd6_rtrequest(req, rt, info)
return;
}
if (req == RTM_RESOLVE &&
(nd6_need_cache(ifp) == 0 || /* stf case */
!nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp))) {
/*
* FreeBSD and BSD/OS often make a cloned host route based
* on a less-specific route (e.g. the default route).
* If the less specific route does not have a "gateway"
* (this is the case when the route just goes to a p2p or an
* stf interface), we'll mistakenly make a neighbor cache for
* the host route, and will see strange neighbor solicitation
* for the corresponding destination. In order to avoid the
* confusion, we check if the destination of the route is
* a neighbor in terms of neighbor discovery, and stop the
* process if not. Additionally, we remove the LLINFO flag
* so that ndp(8) will not try to get the neighbor information
* of the destination.
*/
rt->rt_flags &= ~RTF_LLINFO;
return;
}
switch (req) {
case RTM_ADD:
/*
@ -988,13 +1026,13 @@ nd6_rtrequest(req, rt, info)
if (ln && ln->ln_expire == 0) {
/* kludge for desktops */
#if 0
printf("nd6_rtequest: time.tv_sec is zero; "
printf("nd6_rtrequest: time.tv_sec is zero; "
"treat it as 1\n");
#endif
ln->ln_expire = 1;
}
#endif
if ((rt->rt_flags & RTF_CLONING))
if ((rt->rt_flags & RTF_CLONING) != 0)
break;
}
/*
@ -1026,7 +1064,7 @@ nd6_rtrequest(req, rt, info)
#endif
/* FALLTHROUGH */
case RTM_RESOLVE:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
/*
* Address resolution isn't necessary for a point to
* point link, so we can skip this test for a p2p link.
@ -1091,6 +1129,7 @@ nd6_rtrequest(req, rt, info)
ln->ln_expire = 0;
ln->ln_state = ND6_LLINFO_REACHABLE;
ln->ln_byhint = 0;
mine = 1;
if (macp) {
Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen);
SDL(gate)->sdl_alen = ifp->if_addrlen;
@ -1169,65 +1208,6 @@ nd6_rtrequest(req, rt, info)
}
}
void
nd6_p2p_rtrequest(req, rt, info)
int req;
struct rtentry *rt;
struct rt_addrinfo *info; /* xxx unused */
{
struct sockaddr *gate = rt->rt_gateway;
static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
struct ifnet *ifp = rt->rt_ifp;
struct ifaddr *ifa;
if (rt->rt_flags & RTF_GATEWAY)
return;
switch (req) {
case RTM_ADD:
/*
* There is no backward compatibility :)
*
* if ((rt->rt_flags & RTF_HOST) == 0 &&
* SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
* rt->rt_flags |= RTF_CLONING;
*/
if (rt->rt_flags & RTF_CLONING) {
/*
* Case 1: This route should come from
* a route to interface.
*/
rt_setgate(rt, rt_key(rt),
(struct sockaddr *)&null_sdl);
gate = rt->rt_gateway;
SDL(gate)->sdl_type = ifp->if_type;
SDL(gate)->sdl_index = ifp->if_index;
break;
}
/* Announce a new entry if requested. */
if (rt->rt_flags & RTF_ANNOUNCE)
nd6_na_output(ifp,
&SIN6(rt_key(rt))->sin6_addr,
&SIN6(rt_key(rt))->sin6_addr,
ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
1, NULL);
/* FALLTHROUGH */
case RTM_RESOLVE:
/*
* check if rt_key(rt) is one of my address assigned
* to the interface.
*/
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp,
&SIN6(rt_key(rt))->sin6_addr);
if (ifa) {
if (nd6_useloopback) {
rt->rt_ifp = &loif[0]; /*XXX*/
}
}
break;
}
}
int
nd6_ioctl(cmd, data, ifp)
u_long cmd;
@ -1235,11 +1215,11 @@ nd6_ioctl(cmd, data, ifp)
struct ifnet *ifp;
{
struct in6_drlist *drl = (struct in6_drlist *)data;
struct in6_prlist *prl = (struct in6_prlist *)data;
struct in6_oprlist *oprl = (struct in6_oprlist *)data;
struct in6_ndireq *ndi = (struct in6_ndireq *)data;
struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;
struct in6_ndifreq *ndif = (struct in6_ndifreq *)data;
struct nd_defrouter *dr, any;
struct nd_defrouter *dr;
struct nd_prefix *pr;
struct rtentry *rt;
int i = 0, error = 0;
@ -1247,6 +1227,9 @@ nd6_ioctl(cmd, data, ifp)
switch (cmd) {
case SIOCGDRLST_IN6:
/*
* obsolete API, use sysctl under net.inet6.icmp6
*/
bzero(drl, sizeof(*drl));
s = splsoftnet();
dr = TAILQ_FIRST(&nd_defrouter);
@ -1271,31 +1254,38 @@ nd6_ioctl(cmd, data, ifp)
splx(s);
break;
case SIOCGPRLST_IN6:
/*
* obsolete API, use sysctl under net.inet6.icmp6
*
* XXX the structure in6_prlist was changed in backward-
* incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6,
* in6_prlist is used for nd6_sysctl() - fill_prlist().
*/
/*
* XXX meaning of fields, especialy "raflags", is very
* differnet between RA prefix list and RR/static prefix list.
* how about separating ioctls into two?
*/
bzero(prl, sizeof(*prl));
bzero(oprl, sizeof(*oprl));
s = splsoftnet();
pr = nd_prefix.lh_first;
while (pr && i < PRLSTSIZ) {
struct nd_pfxrouter *pfr;
int j;
prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr;
prl->prefix[i].raflags = pr->ndpr_raf;
prl->prefix[i].prefixlen = pr->ndpr_plen;
prl->prefix[i].vltime = pr->ndpr_vltime;
prl->prefix[i].pltime = pr->ndpr_pltime;
prl->prefix[i].if_index = pr->ndpr_ifp->if_index;
prl->prefix[i].expire = pr->ndpr_expire;
oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr;
oprl->prefix[i].raflags = pr->ndpr_raf;
oprl->prefix[i].prefixlen = pr->ndpr_plen;
oprl->prefix[i].vltime = pr->ndpr_vltime;
oprl->prefix[i].pltime = pr->ndpr_pltime;
oprl->prefix[i].if_index = pr->ndpr_ifp->if_index;
oprl->prefix[i].expire = pr->ndpr_expire;
pfr = pr->ndpr_advrtrs.lh_first;
j = 0;
while (pfr) {
if (j < DRLSTSIZ) {
#define RTRADDR prl->prefix[i].advrtr[j]
#define RTRADDR oprl->prefix[i].advrtr[j]
RTRADDR = pfr->router->rtaddr;
if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) {
/* XXX: hack for KAME */
@ -1311,31 +1301,12 @@ nd6_ioctl(cmd, data, ifp)
j++;
pfr = pfr->pfr_next;
}
prl->prefix[i].advrtrs = j;
prl->prefix[i].origin = PR_ORIG_RA;
oprl->prefix[i].advrtrs = j;
oprl->prefix[i].origin = PR_ORIG_RA;
i++;
pr = pr->ndpr_next;
}
{
struct rr_prefix *rpp;
for (rpp = LIST_FIRST(&rr_prefix); rpp;
rpp = LIST_NEXT(rpp, rp_entry)) {
if (i >= PRLSTSIZ)
break;
prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr;
prl->prefix[i].raflags = rpp->rp_raf;
prl->prefix[i].prefixlen = rpp->rp_plen;
prl->prefix[i].vltime = rpp->rp_vltime;
prl->prefix[i].pltime = rpp->rp_pltime;
prl->prefix[i].if_index = rpp->rp_ifp->if_index;
prl->prefix[i].expire = rpp->rp_expire;
prl->prefix[i].advrtrs = 0;
prl->prefix[i].origin = rpp->rp_origin;
i++;
}
}
splx(s);
break;
@ -1358,15 +1329,9 @@ nd6_ioctl(cmd, data, ifp)
ND_IFINFO(ifp)->flags = ndi->ndi.flags;
break;
case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */
/* flush default router list */
/*
* xxx sumikawa: should not delete route if default
* route equals to the top of default router list
*/
bzero(&any, sizeof(any));
defrouter_delreq(&any, 0);
/* sync kernel routing table with the default router list */
defrouter_reset();
defrouter_select();
/* xxx sumikawa: flush prefix list */
break;
case SIOCSPFXFLUSH_IN6:
{
@ -1375,9 +1340,24 @@ nd6_ioctl(cmd, data, ifp)
s = splsoftnet();
for (pr = nd_prefix.lh_first; pr; pr = next) {
struct in6_ifaddr *ia, *ia_next;
next = pr->ndpr_next;
if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr);
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
continue; /* XXX */
/* do we really have to remove addresses as well? */
for (ia = in6_ifaddr; ia; ia = ia_next) {
/* ia might be removed. keep the next ptr. */
ia_next = ia->ia_next;
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
if (ia->ia6_ndpr == pr)
in6_purgeaddr(&ia->ia_ifa);
}
prelist_remove(pr);
}
splx(s);
@ -1389,17 +1369,12 @@ nd6_ioctl(cmd, data, ifp)
struct nd_defrouter *dr, *next;
s = splsoftnet();
if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) {
/*
* The first entry of the list may be stored in
* the routing table, so we'll delete it later.
*/
for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) {
defrouter_reset();
for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) {
next = TAILQ_NEXT(dr, dr_entry);
defrtrlist_del(dr);
}
defrtrlist_del(TAILQ_FIRST(&nd_defrouter));
}
defrouter_select();
splx(s);
break;
}
@ -1421,12 +1396,12 @@ nd6_ioctl(cmd, data, ifp)
}
s = splsoftnet();
if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) {
if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL ||
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) {
error = EINVAL;
splx(s);
break;
}
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
nbi->state = ln->ln_state;
nbi->asked = ln->ln_asked;
nbi->isrouter = ln->ln_router;
@ -1550,8 +1525,8 @@ fail:
}
if (!is_newentry) {
if ((!olladdr && lladdr) /* (3) */
|| (olladdr && lladdr && llchange)) { /* (5) */
if ((!olladdr && lladdr) || /* (3) */
(olladdr && lladdr && llchange)) { /* (5) */
do_update = 1;
newstate = ND6_LLINFO_STALE;
} else /* (1-2,4) */
@ -1585,8 +1560,7 @@ fail:
* set the 2nd argument as the 1st one.
*/
nd6_output(ifp, ifp, ln->ln_hold,
(struct sockaddr_in6 *)rt_key(rt),
rt);
(struct sockaddr_in6 *)rt_key(rt), rt);
ln->ln_hold = NULL;
}
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
@ -1653,8 +1627,8 @@ fail:
/*
* Mark an entry with lladdr as a router.
*/
if ((!is_newentry && (olladdr || lladdr)) /* (2-5) */
|| (is_newentry && lladdr)) { /* (7) */
if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */
(is_newentry && lladdr)) { /* (7) */
ln->ln_router = 1;
}
break;
@ -1736,8 +1710,8 @@ nd6_output(ifp, origifp, m0, dst, rt0)
*/
if (rt) {
if ((rt->rt_flags & RTF_UP) == 0) {
if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) !=
NULL)
if ((rt0 = rt = rtalloc1((struct sockaddr *)dst,
1)) != NULL)
{
rt->rt_refcnt--;
if (rt->rt_ifp != ifp) {
@ -1755,7 +1729,7 @@ nd6_output(ifp, origifp, m0, dst, rt0)
/*
* We skip link-layer address resolution and NUD
* if the gateway is not a neighbor from ND point
* of view, regardless the value of nd_ifinfo.flags.
* of view, regardless of the value of nd_ifinfo.flags.
* The second condition is a bit tricky; we skip
* if the gateway is our own address, which is
* sometimes used to install a route to a p2p link.
@ -1970,3 +1944,193 @@ nd6_storelladdr(ifp, rt, m, dst, desten)
bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
return(1);
}
int
nd6_sysctl(name, oldp, oldlenp, newp, newlen)
int name;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
size_t ol, l;
int error;
error = 0;
l = 0;
if (newp)
return EPERM;
if (oldp && !oldlenp)
return EINVAL;
ol = oldlenp ? *oldlenp : 0;
switch (name) {
case ICMPV6CTL_ND6_DRLIST:
error = fill_drlist(oldp, oldlenp, ol);
break;
case ICMPV6CTL_ND6_PRLIST:
error = fill_prlist(oldp, oldlenp, ol);
break;
default:
error = ENOPROTOOPT;
break;
}
return(error);
}
static int
fill_drlist(oldp, oldlenp, ol)
void *oldp;
size_t *oldlenp, ol;
{
int error = 0, s;
struct in6_defrouter *d = NULL, *de = NULL;
struct nd_defrouter *dr;
size_t l;
s = splsoftnet();
if (oldp) {
d = (struct in6_defrouter *)oldp;
de = (struct in6_defrouter *)((caddr_t)oldp + *oldlenp);
}
l = 0;
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
dr = TAILQ_NEXT(dr, dr_entry)) {
if (oldp && d + 1 <= de) {
bzero(d, sizeof(*d));
d->rtaddr.sin6_family = AF_INET6;
d->rtaddr.sin6_len = sizeof(struct sockaddr_in6);
d->rtaddr.sin6_addr = dr->rtaddr;
in6_recoverscope(&d->rtaddr, &d->rtaddr.sin6_addr,
dr->ifp);
d->flags = dr->flags;
d->rtlifetime = dr->rtlifetime;
d->expire = dr->expire;
d->if_index = dr->ifp->if_index;
}
l += sizeof(*d);
if (d)
d++;
}
if (oldp) {
*oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */
if (l > ol)
error = ENOMEM;
} else
*oldlenp = l;
splx(s);
return(error);
}
static int
fill_prlist(oldp, oldlenp, ol)
void *oldp;
size_t *oldlenp, ol;
{
int error = 0, s;
struct nd_prefix *pr;
struct in6_prefix *p = NULL;
struct in6_prefix *pe = NULL;
size_t l;
s = splsoftnet();
if (oldp) {
p = (struct in6_prefix *)oldp;
pe = (struct in6_prefix *)((caddr_t)oldp + *oldlenp);
}
l = 0;
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
u_short advrtrs;
size_t advance;
struct sockaddr_in6 *sin6;
struct sockaddr_in6 *s6;
struct nd_pfxrouter *pfr;
if (oldp && p + 1 <= pe)
{
bzero(p, sizeof(*p));
sin6 = (struct sockaddr_in6 *)(p + 1);
p->prefix = pr->ndpr_prefix;
if (in6_recoverscope(&p->prefix,
&p->prefix.sin6_addr, pr->ndpr_ifp) != 0)
log(LOG_ERR,
"scope error in prefix list (%s)\n",
ip6_sprintf(&p->prefix.sin6_addr));
p->raflags = pr->ndpr_raf;
p->prefixlen = pr->ndpr_plen;
p->vltime = pr->ndpr_vltime;
p->pltime = pr->ndpr_pltime;
p->if_index = pr->ndpr_ifp->if_index;
if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)
p->expire = 0;
else {
time_t maxexpire;
/* XXX: we assume time_t is signed. */
maxexpire = (-1) &
~(1 << ((sizeof(maxexpire) * 8) - 1));
if (pr->ndpr_vltime <
maxexpire - pr->ndpr_lastupdate) {
p->expire = pr->ndpr_lastupdate +
pr->ndpr_vltime;
} else
p->expire = maxexpire;
}
p->refcnt = pr->ndpr_refcnt;
p->flags = pr->ndpr_stateflags;
p->origin = PR_ORIG_RA;
advrtrs = 0;
for (pfr = pr->ndpr_advrtrs.lh_first; pfr;
pfr = pfr->pfr_next) {
if ((void *)&sin6[advrtrs + 1] > (void *)pe) {
advrtrs++;
continue;
}
s6 = &sin6[advrtrs];
s6->sin6_family = AF_INET6;
s6->sin6_len = sizeof(struct sockaddr_in6);
s6->sin6_addr = pfr->router->rtaddr;
in6_recoverscope(s6, &s6->sin6_addr,
pfr->router->ifp);
advrtrs++;
}
p->advrtrs = advrtrs;
}
else {
advrtrs = 0;
for (pfr = pr->ndpr_advrtrs.lh_first; pfr;
pfr = pfr->pfr_next)
advrtrs++;
}
advance = sizeof(*p) + sizeof(*sin6) * advrtrs;
l += advance;
if (p)
p = (struct in6_prefix *)((caddr_t)p + advance);
}
if (oldp) {
*oldlenp = l; /* (caddr_t)d - (caddr_t)oldp */
if (l > ol)
error = ENOMEM;
} else
*oldlenp = l;
splx(s);
return(error);
}

View File

@ -1,5 +1,5 @@
/* $NetBSD: nd6.h,v 1.30 2002/06/07 02:31:04 itojun Exp $ */
/* $KAME: nd6.h,v 1.93 2002/06/05 00:56:22 itojun Exp $ */
/* $NetBSD: nd6.h,v 1.31 2002/06/08 21:22:34 itojun Exp $ */
/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -93,6 +93,7 @@ struct nd_ifinfo {
};
#define ND6_IFF_PERFORMNUD 0x1
#define ND6_IFF_ACCEPT_RTADV 0x2
#ifdef _KERNEL
#define ND_IFINFO(ifp) \
@ -126,7 +127,16 @@ struct in6_drlist {
} defrouter[DRLSTSIZ];
};
struct in6_prlist {
struct in6_defrouter {
struct sockaddr_in6 rtaddr;
u_char flags;
u_short rtlifetime;
u_long expire;
u_short if_index;
};
#ifdef _KERNEL
struct in6_oprlist {
char ifname[IFNAMSIZ];
struct {
struct in6_addr prefix;
@ -141,6 +151,38 @@ struct in6_prlist {
struct in6_addr advrtr[DRLSTSIZ]; /* XXX: explicit limit */
} prefix[PRLSTSIZ];
};
#endif
struct in6_prlist {
char ifname[IFNAMSIZ];
struct {
struct in6_addr prefix;
struct prf_ra raflags;
u_char prefixlen;
u_char origin;
u_int32_t vltime;
u_int32_t pltime;
time_t expire;
u_short if_index;
u_short advrtrs; /* number of advertisement routers */
struct in6_addr advrtr[DRLSTSIZ]; /* XXX: explicit limit */
} prefix[PRLSTSIZ];
};
struct in6_prefix {
struct sockaddr_in6 prefix;
struct prf_ra raflags;
u_char prefixlen;
u_char origin;
u_int32_t vltime;
u_int32_t pltime;
time_t expire;
u_int32_t flags;
int refcnt;
u_short if_index;
u_short advrtrs; /* number of advertisement routers */
/* struct sockaddr_in6 advrtr[] */
};
#ifdef _KERNEL
struct in6_ondireq {
@ -169,6 +211,10 @@ struct in6_ndifreq {
u_long ifindex;
};
/* Prefix status */
#define NDPRF_ONLINK 0x1
#define NDPRF_DETACHED 0x2
#define NDPRF_HOME 0x4
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */
@ -192,10 +238,11 @@ TAILQ_HEAD(nd_drhead, nd_defrouter);
struct nd_defrouter {
TAILQ_ENTRY(nd_defrouter) dr_entry;
struct in6_addr rtaddr;
u_char flags;
u_char flags; /* flags on RA message */
u_short rtlifetime;
u_long expire;
struct ifnet *ifp;
int installed; /* is installed into kernel routing table */
};
struct nd_prefix {
@ -203,19 +250,20 @@ struct nd_prefix {
LIST_ENTRY(nd_prefix) ndpr_entry;
struct sockaddr_in6 ndpr_prefix; /* prefix */
struct in6_addr ndpr_mask; /* netmask derived from the prefix */
struct in6_addr ndpr_addr; /* address that is derived from the prefix */
u_int32_t ndpr_vltime; /* advertised valid lifetime */
u_int32_t ndpr_pltime; /* advertised preferred lifetime */
time_t ndpr_expire; /* expiration time of the prefix */
time_t ndpr_preferred; /* preferred time of the prefix */
time_t ndpr_lastupdate; /* reception time of last advertisement */
struct prf_ra ndpr_flags;
u_int32_t ndpr_stateflags; /* actual state flags */
/* list of routers that advertise the prefix: */
LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs;
u_char ndpr_plen;
struct ndpr_stateflags {
/* if this prefix can be regarded as on-link */
u_char onlink : 1;
} ndpr_stateflags;
int ndpr_refcnt; /* reference couter from addresses */
};
#define ndpr_next ndpr_entry.le_next
@ -223,15 +271,7 @@ struct nd_prefix {
#define ndpr_raf ndpr_flags
#define ndpr_raf_onlink ndpr_flags.onlink
#define ndpr_raf_auto ndpr_flags.autonomous
#define ndpr_statef_onlink ndpr_stateflags.onlink
#define ndpr_statef_addmark ndpr_stateflags.addmark
/*
* We keep expired prefix for certain amount of time, for validation purposes.
* 1800s = MaxRtrAdvInterval
*/
#define NDPR_KEEP_EXPIRED (1800 * 2)
#define ndpr_raf_router ndpr_flags.router
/*
* Message format for use in obtaining information about prefixes
@ -259,9 +299,6 @@ struct inet6_ndpr_msghdr {
#define prm_rrf_decrvalid prm_flags.prf_rr.decrvalid
#define prm_rrf_decrprefd prm_flags.prf_rr.decrprefd
#define ifpr2ndpr(ifpr) ((struct nd_prefix *)(ifpr))
#define ndpr2ifpr(ndpr) ((struct ifprefix *)(ndpr))
struct nd_pfxrouter {
LIST_ENTRY(nd_pfxrouter) pfr_entry;
#define pfr_next pfr_entry.le_next
@ -332,7 +369,6 @@ void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int));
int nd6_resolve __P((struct ifnet *, struct rtentry *,
struct mbuf *, struct sockaddr *, u_char *));
void nd6_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
void nd6_p2p_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
int nd6_ioctl __P((u_long, caddr_t, struct ifnet *));
struct rtentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *,
char *, int, int, int));
@ -340,6 +376,7 @@ int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *,
struct sockaddr_in6 *, struct rtentry *));
int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *,
struct sockaddr *, u_char *));
int nd6_sysctl __P((int, void *, size_t *, void *, size_t));
int nd6_need_cache __P((struct ifnet *));
/* nd6_nbr.c */
@ -359,15 +396,19 @@ void nd6_rs_input __P((struct mbuf *, int, int));
void nd6_ra_input __P((struct mbuf *, int, int));
void prelist_del __P((struct nd_prefix *));
void defrouter_addreq __P((struct nd_defrouter *));
void defrouter_delreq __P((struct nd_defrouter *, int));
void defrouter_reset __P((void));
void defrouter_select __P((void));
void defrtrlist_del __P((struct nd_defrouter *));
void prelist_remove __P((struct nd_prefix *));
int prelist_update __P((struct nd_prefix *, struct nd_defrouter *,
struct mbuf *));
int nd6_prelist_add __P((struct nd_prefix *, struct nd_defrouter *,
struct nd_prefix **));
int nd6_prefix_onlink __P((struct nd_prefix *));
int nd6_prefix_offlink __P((struct nd_prefix *));
void pfxlist_onlink_check __P((void));
struct nd_defrouter *defrouter_lookup __P((struct in6_addr *,
struct ifnet *));
struct nd_defrouter *defrouter_lookup __P((struct in6_addr *, struct ifnet *));
struct nd_prefix *nd6_prefix_lookup __P((struct nd_prefix *));
int in6_ifdel __P((struct ifnet *, struct in6_addr *));
int in6_init_prefix_ltimes __P((struct nd_prefix *ndpr));
void rt6_flush __P((struct in6_addr *, struct ifnet *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_nbr.c,v 1.38 2002/06/07 07:38:51 itojun Exp $ */
/* $NetBSD: nd6_nbr.c,v 1.39 2002/06/08 21:22:34 itojun 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.38 2002/06/07 07:38:51 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.39 2002/06/08 21:22:34 itojun Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -105,6 +105,7 @@ nd6_ns_input(m, off, icmp6len)
struct ifaddr *ifa;
int lladdrlen = 0;
int anycast = 0, proxy = 0, tentative = 0;
int router = ip6_forwarding;
int tlladdr;
union nd_opts ndopts;
struct sockaddr_dl *proxydl = NULL;
@ -132,11 +133,11 @@ nd6_ns_input(m, off, icmp6len)
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
/* dst has to be solicited node multicast address. */
if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL
/* don't check ifindex portion */
&& daddr6.s6_addr32[1] == 0
&& daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE
&& daddr6.s6_addr8[12] == 0xff) {
if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
daddr6.s6_addr32[1] == 0 &&
daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
daddr6.s6_addr8[12] == 0xff) {
; /* good */
} else {
nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
@ -224,6 +225,7 @@ nd6_ns_input(m, off, icmp6len)
if (ifa) {
proxy = 1;
proxydl = SDL(rt->rt_gateway);
router = 0; /* XXX */
}
}
if (rt)
@ -244,16 +246,14 @@ nd6_ns_input(m, off, icmp6len)
goto freeit;
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
nd6log((LOG_INFO,
"nd6_ns_input: lladdrlen mismatch for %s "
nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
"(if %d, NS packet %d)\n",
ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
goto bad;
}
if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
nd6log((LOG_INFO,
"nd6_ns_input: duplicate IP6 address %s\n",
nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
ip6_sprintf(&saddr6)));
goto freeit;
}
@ -296,9 +296,8 @@ nd6_ns_input(m, off, icmp6len)
saddr6 = in6addr_linklocal_allnodes;
saddr6.s6_addr16[1] = htons(ifp->if_index);
nd6_na_output(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr)
? 0 : ND_NA_FLAG_OVERRIDE)
| (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
(router ? ND_NA_FLAG_ROUTER : 0),
tlladdr, (struct sockaddr *)proxydl);
goto freeit;
}
@ -306,9 +305,8 @@ nd6_ns_input(m, off, icmp6len)
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
nd6_na_output(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE)
| (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0)
| ND_NA_FLAG_SOLICITED,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
(router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
tlladdr, (struct sockaddr *)proxydl);
freeit:
m_freem(m);
@ -341,11 +339,14 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
struct mbuf *m;
struct ip6_hdr *ip6;
struct nd_neighbor_solicit *nd_ns;
struct in6_ifaddr *ia = NULL;
struct sockaddr_in6 src_sa, dst_sa;
struct ip6_moptions im6o;
int icmp6len;
int maxlen;
caddr_t mac;
struct route_in6 ro;
bzero(&ro, sizeof(ro));
if (IN6_IS_ADDR_MULTICAST(taddr6))
return;
@ -393,16 +394,22 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
/* ip6->ip6_plen will be set later */
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 255;
/* determine the source and destination addresses */
bzero(&src_sa, sizeof(src_sa));
bzero(&dst_sa, sizeof(dst_sa));
src_sa.sin6_family = dst_sa.sin6_family = AF_INET6;
src_sa.sin6_len = dst_sa.sin6_len = sizeof(struct sockaddr_in6);
if (daddr6)
ip6->ip6_dst = *daddr6;
dst_sa.sin6_addr = *daddr6;
else {
ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
ip6->ip6_dst.s6_addr32[1] = 0;
ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
ip6->ip6_dst.s6_addr8[12] = 0xff;
dst_sa.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
dst_sa.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
dst_sa.sin6_addr.s6_addr32[1] = 0;
dst_sa.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
dst_sa.sin6_addr.s6_addr32[3] = taddr6->s6_addr32[3];
dst_sa.sin6_addr.s6_addr8[12] = 0xff;
}
ip6->ip6_dst = dst_sa.sin6_addr;
if (!dad) {
/*
* RFC2461 7.2.2:
@ -417,7 +424,7 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
* (saddr6), if:
* - saddr6 is given from the caller (by giving "ln"), and
* - saddr6 belongs to the outgoing interface.
* Otherwise, we perform a scope-wise match.
* Otherwise, we perform the source address selection as usual.
*/
struct ip6_hdr *hip6; /* hold ip6 */
struct in6_addr *saddr6;
@ -432,22 +439,34 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
} else
saddr6 = NULL;
if (saddr6 && in6ifa_ifpwithaddr(ifp, saddr6))
bcopy(saddr6, &ip6->ip6_src, sizeof(*saddr6));
src_sa.sin6_addr = *saddr6;
else {
ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
if (ia == NULL) {
m_freem(m);
return;
struct in6_addr *src0;
int error;
bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
src0 = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL,
&error);
if (src0 == NULL) {
nd6log((LOG_DEBUG,
"nd6_ns_output: source can't be "
"determined: dst=%s, error=%d\n",
ip6_sprintf(&dst_sa.sin6_addr), error));
goto bad;
}
ip6->ip6_src = ia->ia_addr.sin6_addr;
src_sa.sin6_addr = *src0;
}
} else {
/*
* Source address for DAD packet must always be IPv6
* unspecified address. (0::0)
* We actually don't have to 0-clear the address (we did it
* above), but we do so here explicitly to make the intention
* clearer.
*/
bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
bzero(&src_sa.sin6_addr, sizeof(src_sa.sin6_addr));
}
ip6->ip6_src = src_sa.sin6_addr;
nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
nd_ns->nd_ns_code = 0;
@ -486,31 +505,36 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
ip6->ip6_plen = htons((u_short)icmp6len);
nd_ns->nd_ns_cksum = 0;
nd_ns->nd_ns_cksum
= in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
nd_ns->nd_ns_cksum =
in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
#ifdef IPSEC
/* Don't lookup socket */
(void)ipsec_setsocket(m, NULL);
#endif
ip6_output(m, NULL, NULL, 0, &im6o, NULL);
ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL);
icmp6_ifstat_inc(ifp, ifs6_out_msg);
icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
if (ro.ro_rt) { /* we don't cache this route. */
RTFREE(ro.ro_rt);
}
return;
#if 0
bad:
if (ro.ro_rt) {
RTFREE(ro.ro_rt);
}
m_freem(m);
return;
#endif
}
/*
* Neighbor advertisement input handling.
*
* Based on RFC 2461
long time_second = time.tv_sec;
* Based on RFC 2462 (duplicated address detection)
*
* the following items are not implemented yet:
@ -576,8 +600,7 @@ nd6_na_input(m, off, icmp6len)
ip6_sprintf(&taddr6)));
goto bad;
}
if (IN6_IS_ADDR_MULTICAST(&daddr6))
if (is_solicited) {
if (is_solicited && IN6_IS_ADDR_MULTICAST(&daddr6)) {
nd6log((LOG_ERR,
"nd6_na_input: a solicited adv is multicasted\n"));
goto bad;
@ -623,15 +646,15 @@ nd6_na_input(m, off, icmp6len)
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
nd6log((LOG_INFO,
"nd6_na_input: lladdrlen mismatch for %s "
"(if %d, NA packet %d)\n",
ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "
"(if %d, NA packet %d)\n", ip6_sprintf(&taddr6),
ifp->if_addrlen, lladdrlen - 2));
goto bad;
}
/*
* If no neighbor cache entry is found, NA SHOULD silently be discarded.
* If no neighbor cache entry is found, NA SHOULD silently be
* discarded.
*/
rt = nd6_lookup(&taddr6, 0, ifp);
if ((rt == NULL) ||
@ -788,7 +811,7 @@ nd6_na_input(m, off, icmp6len)
ln->ln_asked = 0;
if (ln->ln_hold) {
/*
* we assume ifp is not a p2p here, so just set the 2nd
* we assume ifp is not a loopback here, so just set the 2nd
* argument as the 1st one.
*/
nd6_output(ifp, ifp, ln->ln_hold,
@ -825,11 +848,15 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
struct mbuf *m;
struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na;
struct in6_ifaddr *ia = NULL;
struct ip6_moptions im6o;
int icmp6len;
int maxlen;
struct sockaddr_in6 src_sa, dst_sa;
struct in6_addr *src0;
int icmp6len, maxlen, error;
caddr_t mac;
struct route_in6 ro;
mac = NULL;
bzero(&ro, sizeof(ro));
/* estimate the size of message */
maxlen = sizeof(*ip6) + sizeof(*nd_na);
@ -873,26 +900,36 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 255;
bzero(&src_sa, sizeof(src_sa));
bzero(&dst_sa, sizeof(dst_sa));
src_sa.sin6_len = dst_sa.sin6_len = sizeof(struct sockaddr_in6);
src_sa.sin6_family = dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_addr = *daddr6;
if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
/* reply to DAD */
ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
ip6->ip6_dst.s6_addr32[1] = 0;
ip6->ip6_dst.s6_addr32[2] = 0;
ip6->ip6_dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
dst_sa.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
dst_sa.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
dst_sa.sin6_addr.s6_addr32[1] = 0;
dst_sa.sin6_addr.s6_addr32[2] = 0;
dst_sa.sin6_addr.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
flags &= ~ND_NA_FLAG_SOLICITED;
} else
ip6->ip6_dst = *daddr6;
}
ip6->ip6_dst = dst_sa.sin6_addr;
/*
* Select a source whose scope is the same as that of the dest.
*/
ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
if (ia == NULL) {
m_freem(m);
return;
bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
src0 = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &error);
if (src0 == NULL) {
nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
"determined: dst=%s, error=%d\n",
ip6_sprintf(&dst_sa.sin6_addr), error));
goto bad;
}
ip6->ip6_src = ia->ia_addr.sin6_addr;
src_sa.sin6_addr = *src0;
ip6->ip6_src = src_sa.sin6_addr;
nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
nd_na->nd_na_code = 0;
@ -907,7 +944,6 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
* target lladdr option SHOULD NOT be included.
*/
if (tlladdr) {
mac = NULL;
/*
* sdl0 != NULL indicates proxy NA. If we do proxy, use
* lladdr in sdl0. If we are not proxying (sending NA for
@ -954,6 +990,18 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
icmp6_ifstat_inc(ifp, ifs6_out_msg);
icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
if (ro.ro_rt) { /* we don't cache this route. */
RTFREE(ro.ro_rt);
}
return;
bad:
if (ro.ro_rt) {
RTFREE(ro.ro_rt);
}
m_freem(m);
return;
}
caddr_t
@ -965,6 +1013,9 @@ nd6_ifptomac(ifp)
case IFT_ETHER:
case IFT_FDDI:
case IFT_IEEE1394:
case IFT_PROPVIRTUAL:
case IFT_L2VLAN:
case IFT_IEEE80211:
return LLADDR(ifp->if_sadl);
break;
default:

File diff suppressed because it is too large Load Diff