bring in recent KAME changes (only important and stable ones, as usual).
- remove net.inet6.ip6.nd6_proxyall. introduce proxy NDP code works just like "arp -s". - revise source address selection. be more careful about use of yet-to-be-valid addresses as source. - as router, transmit ICMP6_DST_UNREACH_BEYONDSCOPE against out-of-scope packet forwarding attempt. - path MTU discovery takes care of routing header properly. - be more strict about mbuf chain parsing.
This commit is contained in:
parent
2925a0d65b
commit
1450d6e643
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: icmp6.h,v 1.4 2000/02/06 11:11:30 itojun Exp $ */
|
||||
/* $NetBSD: icmp6.h,v 1.5 2000/02/26 08:39:18 itojun Exp $ */
|
||||
/* $KAME: icmp6.h,v 1.6 2000/02/24 16:34:46 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -469,12 +470,12 @@ struct icmp6_filter {
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define ICMP6_FILTER_SETPASSALL(filterp) \
|
||||
{ \
|
||||
do { \
|
||||
int i; u_char *p; \
|
||||
p = (u_char *)filterp; \
|
||||
for (i = 0; i < sizeof(struct icmp6_filter); i++) \
|
||||
p[i] = 0xff; \
|
||||
}
|
||||
} while (0)
|
||||
#define ICMP6_FILTER_SETBLOCKALL(filterp) \
|
||||
bzero(filterp, sizeof(struct icmp6_filter))
|
||||
#else /* _KERNEL */
|
||||
@ -525,7 +526,7 @@ struct icmp6stat {
|
||||
#define ICMPV6CTL_ND6_UMAXTRIES 9
|
||||
#define ICMPV6CTL_ND6_MMAXTRIES 10
|
||||
#define ICMPV6CTL_ND6_USELOOPBACK 11
|
||||
#define ICMPV6CTL_ND6_PROXYALL 12
|
||||
/*#define ICMPV6CTL_ND6_PROXYALL 12 obsoleted, do not reuse here */
|
||||
#define ICMPV6CTL_NODEINFO 13
|
||||
#define ICMPV6CTL_MAXID 14
|
||||
|
||||
@ -542,7 +543,7 @@ struct icmp6stat {
|
||||
{ "nd6_umaxtries", CTLTYPE_INT }, \
|
||||
{ "nd6_mmaxtries", CTLTYPE_INT }, \
|
||||
{ "nd6_useloopback", CTLTYPE_INT }, \
|
||||
{ "nd6_proxyall", CTLTYPE_INT }, \
|
||||
{ 0, 0 }, \
|
||||
{ "nodeinfo", CTLTYPE_INT }, \
|
||||
}
|
||||
|
||||
@ -560,7 +561,7 @@ struct icmp6stat {
|
||||
&nd6_umaxtries, \
|
||||
&nd6_mmaxtries, \
|
||||
&nd6_useloopback, \
|
||||
&nd6_proxyall, \
|
||||
0, \
|
||||
&icmp6_nodeinfo, \
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: icmp6.c,v 1.22 2000/02/17 10:59:38 darrenr Exp $ */
|
||||
/* $NetBSD: icmp6.c,v 1.23 2000/02/26 08:39:19 itojun Exp $ */
|
||||
/* $KAME: icmp6.c,v 1.70 2000/02/26 07:01:11 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -117,6 +118,8 @@ static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
|
||||
extern int pmtu_expire;
|
||||
|
||||
static int icmp6_rip6_input __P((struct mbuf **, int));
|
||||
static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *,
|
||||
struct mbuf *));
|
||||
static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
|
||||
static const char *icmp6_redirect_diag __P((struct in6_addr *,
|
||||
struct in6_addr *, struct in6_addr *));
|
||||
@ -155,10 +158,10 @@ icmp6_error(m, type, code, param)
|
||||
|
||||
icmp6stat.icp6s_error++;
|
||||
|
||||
#ifdef M_DECRYPTED /*not openbsd*/
|
||||
if (m->m_flags & M_DECRYPTED)
|
||||
if (m->m_flags & M_DECRYPTED) {
|
||||
icmp6stat.icp6s_canterror++;
|
||||
goto freeit;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
|
||||
@ -408,12 +411,21 @@ icmp6_input(mp, offp, proto)
|
||||
break;
|
||||
case ICMP6_DST_UNREACH_ADMIN:
|
||||
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
|
||||
case ICMP6_DST_UNREACH_ADDR:
|
||||
code = PRC_UNREACH_HOST;
|
||||
code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
|
||||
break;
|
||||
case ICMP6_DST_UNREACH_ADDR:
|
||||
code = PRC_HOSTDEAD;
|
||||
break;
|
||||
#ifdef COMPAT_RFC1885
|
||||
case ICMP6_DST_UNREACH_NOTNEIGHBOR:
|
||||
code = PRC_UNREACH_SRCFAIL;
|
||||
break;
|
||||
#else
|
||||
case ICMP6_DST_UNREACH_BEYONDSCOPE:
|
||||
/* I mean "source address was incorrect." */
|
||||
code = PRC_PARAMPROB;
|
||||
break;
|
||||
#endif
|
||||
case ICMP6_DST_UNREACH_NOPORT:
|
||||
code = PRC_UNREACH_PORT;
|
||||
break;
|
||||
@ -427,55 +439,14 @@ icmp6_input(mp, offp, proto)
|
||||
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
|
||||
if (code != 0)
|
||||
goto badcode;
|
||||
{
|
||||
u_int mtu = ntohl(icmp6->icmp6_mtu);
|
||||
struct rtentry *rt = NULL;
|
||||
struct sockaddr_in6 sin6;
|
||||
|
||||
if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
goto freeit;
|
||||
}
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off,
|
||||
sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr),
|
||||
IPPROTO_DONE);
|
||||
icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
|
||||
sizeof(*icmp6) + sizeof(struct ip6_hdr));
|
||||
if (icmp6 == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
code = PRC_MSGSIZE;
|
||||
bzero(&sin6, sizeof(sin6));
|
||||
sin6.sin6_family = PF_INET6;
|
||||
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sin6.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
|
||||
rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/
|
||||
if (!rt || (rt->rt_flags & RTF_HOST) == 0) {
|
||||
if (rt)
|
||||
RTFREE(rt);
|
||||
rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
|
||||
}
|
||||
|
||||
if (rt && (rt->rt_flags & RTF_HOST)
|
||||
&& !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
|
||||
if (mtu < IPV6_MMTU) {
|
||||
/* xxx */
|
||||
rt->rt_rmx.rmx_locks |= RTV_MTU;
|
||||
} else if (mtu < rt->rt_ifp->if_mtu &&
|
||||
rt->rt_rmx.rmx_mtu > mtu) {
|
||||
rt->rt_rmx.rmx_mtu = mtu;
|
||||
}
|
||||
}
|
||||
if (rt)
|
||||
RTFREE(rt);
|
||||
|
||||
/*
|
||||
* Updating the path MTU will be done after examining
|
||||
* intermediate extension headers.
|
||||
*/
|
||||
goto deliver;
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP6_TIME_EXCEEDED:
|
||||
@ -518,12 +489,28 @@ icmp6_input(mp, offp, proto)
|
||||
if ((n->m_flags & M_EXT) != 0
|
||||
|| n->m_len < off + sizeof(struct icmp6_hdr)) {
|
||||
struct mbuf *n0 = n;
|
||||
const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
|
||||
|
||||
/*
|
||||
* Prepare an internal mbuf. m_pullup() doesn't
|
||||
* always copy the length we specified.
|
||||
*/
|
||||
if (maxlen >= MCLBYTES) {
|
||||
#ifdef DIAGNOSTIC
|
||||
printf("MCLBYTES too small\n");
|
||||
#endif
|
||||
/* Give up remote */
|
||||
m_freem(n0);
|
||||
break;
|
||||
}
|
||||
MGETHDR(n, M_DONTWAIT, n0->m_type);
|
||||
if (n && maxlen >= MHLEN) {
|
||||
MCLGET(n, M_DONTWAIT);
|
||||
if ((n->m_flags & M_EXT) == 0) {
|
||||
m_free(n);
|
||||
n = NULL;
|
||||
}
|
||||
}
|
||||
if (n == NULL) {
|
||||
/* Give up remote */
|
||||
m_freem(n0);
|
||||
@ -576,8 +563,13 @@ icmp6_input(mp, offp, proto)
|
||||
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
|
||||
else
|
||||
icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
|
||||
mld6_input(m, off);
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
mld6_input(m, off);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
mld6_input(n, off);
|
||||
/* m stays. */
|
||||
break;
|
||||
|
||||
@ -591,7 +583,7 @@ icmp6_input(mp, offp, proto)
|
||||
case MLD6_MTRACE:
|
||||
/* XXX: these two are experimental. not officially defind. */
|
||||
/* XXX: per-interface statistics? */
|
||||
break; /* just pass it to the userland daemon */
|
||||
break; /* just pass it to applications */
|
||||
|
||||
case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
|
||||
{
|
||||
@ -621,12 +613,32 @@ icmp6_input(mp, offp, proto)
|
||||
noff = sizeof(struct ip6_hdr);
|
||||
} else {
|
||||
u_char *p;
|
||||
int maxlen, maxhlen;
|
||||
|
||||
maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
|
||||
if (maxlen >= MCLBYTES) {
|
||||
#ifdef DIAGNOSTIC
|
||||
printf("MCLBYTES too small\n");
|
||||
#endif
|
||||
/* Give up remote */
|
||||
break;
|
||||
}
|
||||
MGETHDR(n, M_DONTWAIT, m->m_type);
|
||||
if (n && maxlen > MHLEN) {
|
||||
MCLGET(n, M_DONTWAIT);
|
||||
if ((n->m_flags & M_EXT) == 0) {
|
||||
m_free(n);
|
||||
n = NULL;
|
||||
}
|
||||
}
|
||||
if (n == NULL) {
|
||||
/* Give up remote */
|
||||
break;
|
||||
}
|
||||
n->m_len = 0;
|
||||
maxhlen = M_TRAILINGSPACE(n) - maxlen;
|
||||
if (maxhlen > hostnamelen)
|
||||
maxhlen = hostnamelen;
|
||||
/*
|
||||
* Copy IPv6 and ICMPv6 only.
|
||||
*/
|
||||
@ -636,11 +648,11 @@ icmp6_input(mp, offp, proto)
|
||||
bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
|
||||
p = (u_char *)(nicmp6 + 1);
|
||||
bzero(p, 4);
|
||||
bcopy(hostname, p + 4, hostnamelen);
|
||||
bcopy(hostname, p + 4, maxhlen);
|
||||
noff = sizeof(struct ip6_hdr);
|
||||
M_COPY_PKTHDR(n, m); /* just for recvif */
|
||||
n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
|
||||
sizeof(struct icmp6_hdr) + 4 + hostnamelen;
|
||||
sizeof(struct icmp6_hdr) + 4 + maxhlen;
|
||||
nicmp6->icmp6_type = ICMP6_WRUREPLY;
|
||||
nicmp6->icmp6_code = 0;
|
||||
}
|
||||
@ -664,8 +676,13 @@ icmp6_input(mp, offp, proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_router_solicit))
|
||||
goto badlen;
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
|
||||
nd6_rs_input(m, off, icmp6len);
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
nd6_rs_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
nd6_rs_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
break;
|
||||
|
||||
@ -675,8 +692,13 @@ icmp6_input(mp, offp, proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_router_advert))
|
||||
goto badlen;
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
|
||||
nd6_ra_input(m, off, icmp6len);
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
nd6_ra_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
nd6_ra_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
break;
|
||||
|
||||
@ -686,8 +708,13 @@ icmp6_input(mp, offp, proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_neighbor_solicit))
|
||||
goto badlen;
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
|
||||
nd6_ns_input(m, off, icmp6len);
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
nd6_ns_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
nd6_ns_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
break;
|
||||
|
||||
@ -697,8 +724,13 @@ icmp6_input(mp, offp, proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_neighbor_advert))
|
||||
goto badlen;
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
|
||||
nd6_na_input(m, off, icmp6len);
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
nd6_na_input(m, off, icmp6len);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
nd6_na_input(n, off, icmp6len);
|
||||
/* m stays. */
|
||||
break;
|
||||
|
||||
@ -708,7 +740,13 @@ icmp6_input(mp, offp, proto)
|
||||
goto badcode;
|
||||
if (icmp6len < sizeof(struct nd_redirect))
|
||||
goto badlen;
|
||||
icmp6_redirect_input(m, off);
|
||||
if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
|
||||
/* give up local */
|
||||
icmp6_redirect_input(m, off);
|
||||
m = NULL;
|
||||
goto freeit;
|
||||
}
|
||||
icmp6_redirect_input(n, off);
|
||||
/* m stays. */
|
||||
break;
|
||||
|
||||
@ -764,19 +802,20 @@ icmp6_input(mp, offp, proto)
|
||||
int eoff = off + sizeof(struct icmp6_hdr) +
|
||||
sizeof(struct ip6_hdr);
|
||||
struct ip6ctlparam ip6cp;
|
||||
struct in6_addr *finaldst = NULL;
|
||||
int icmp6type = icmp6->icmp6_type;
|
||||
struct ip6_frag *fh;
|
||||
struct ip6_rthdr *rth;
|
||||
struct ip6_rthdr0 *rth0;
|
||||
int rthlen;
|
||||
|
||||
while (1) { /* XXX: should avoid inf. loop explicitly? */
|
||||
struct ip6_ext *eh;
|
||||
|
||||
switch(nxt) {
|
||||
case IPPROTO_ESP:
|
||||
case IPPROTO_NONE:
|
||||
goto passit;
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_AH:
|
||||
case IPPROTO_FRAGMENT:
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, 0, eoff +
|
||||
sizeof(struct ip6_ext),
|
||||
@ -791,15 +830,105 @@ icmp6_input(mp, offp, proto)
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nxt == IPPROTO_AH)
|
||||
eoff += (eh->ip6e_len + 2) << 2;
|
||||
else if (nxt == IPPROTO_FRAGMENT)
|
||||
eoff += sizeof(struct ip6_frag);
|
||||
else
|
||||
eoff += (eh->ip6e_len + 1) << 3;
|
||||
nxt = eh->ip6e_nxt;
|
||||
break;
|
||||
case IPPROTO_ROUTING:
|
||||
/*
|
||||
* When the erroneous packet contains a
|
||||
* routing header, we should examine the
|
||||
* header to determine the final destination.
|
||||
* Otherwise, we can't properly update
|
||||
* information that depends on the final
|
||||
* destination (e.g. path MTU).
|
||||
*/
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
|
||||
IPPROTO_DONE);
|
||||
rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
|
||||
+ eoff);
|
||||
#else
|
||||
IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
|
||||
eoff, sizeof(*rth));
|
||||
if (rth == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
rthlen = (rth->ip6r_len + 1) << 3;
|
||||
/*
|
||||
* XXX: currently there is no
|
||||
* officially defined type other
|
||||
* than type-0.
|
||||
* Note that if the segment left field
|
||||
* is 0, all intermediate hops must
|
||||
* have been passed.
|
||||
*/
|
||||
if (rth->ip6r_segleft &&
|
||||
rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
|
||||
int hops;
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
|
||||
IPPROTO_DONE);
|
||||
rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
|
||||
#else
|
||||
IP6_EXTHDR_GET(rth0,
|
||||
struct ip6_rthdr0 *, m,
|
||||
eoff, rthlen);
|
||||
if (rth0 == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
/* just ignore a bogus header */
|
||||
if ((rth0->ip6r0_len % 2) == 0 &&
|
||||
(hops = rth0->ip6r0_len/2))
|
||||
finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
|
||||
}
|
||||
eoff += rthlen;
|
||||
nxt = rth->ip6r_nxt;
|
||||
break;
|
||||
case IPPROTO_FRAGMENT:
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, 0, eoff +
|
||||
sizeof(struct ip6_frag),
|
||||
IPPROTO_DONE);
|
||||
fh = (struct ip6_frag *)(mtod(m, caddr_t)
|
||||
+ eoff);
|
||||
#else
|
||||
IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
|
||||
eoff, sizeof(*fh));
|
||||
if (fh == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Data after a fragment header is meaningless
|
||||
* unless it is the first fragment, but
|
||||
* we'll go to the notify label for path MTU
|
||||
* discovery.
|
||||
*/
|
||||
if (fh->ip6f_offlg & IP6F_OFF_MASK)
|
||||
goto notify;
|
||||
|
||||
eoff += sizeof(struct ip6_frag);
|
||||
nxt = fh->ip6f_nxt;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* This case includes ESP and the No Next
|
||||
* Header. In such cases going to the notify
|
||||
* label does not have any meaning
|
||||
* (i.e. ctlfunc will be NULL), but we go
|
||||
* anyway since we might have to update
|
||||
* path MTU information.
|
||||
*/
|
||||
goto notify;
|
||||
}
|
||||
}
|
||||
@ -814,6 +943,12 @@ icmp6_input(mp, offp, proto)
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
if (icmp6type == ICMP6_PACKET_TOO_BIG) {
|
||||
if (finaldst == NULL)
|
||||
finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
|
||||
icmp6_mtudisc_update(finaldst, icmp6, m);
|
||||
}
|
||||
|
||||
ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
|
||||
(inet6sw[ip6_protox[nxt]].pr_ctlinput);
|
||||
if (ctlfunc) {
|
||||
@ -834,7 +969,6 @@ icmp6_input(mp, offp, proto)
|
||||
break;
|
||||
}
|
||||
|
||||
passit:
|
||||
icmp6_rip6_input(&m, *offp);
|
||||
return IPPROTO_DONE;
|
||||
|
||||
@ -843,6 +977,42 @@ icmp6_input(mp, offp, proto)
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
|
||||
static void
|
||||
icmp6_mtudisc_update(dst, icmp6, m)
|
||||
struct in6_addr *dst;
|
||||
struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */
|
||||
struct mbuf *m; /* currently unused but added for scoped addrs */
|
||||
{
|
||||
u_int mtu = ntohl(icmp6->icmp6_mtu);
|
||||
struct rtentry *rt = NULL;
|
||||
struct sockaddr_in6 sin6;
|
||||
|
||||
bzero(&sin6, sizeof(sin6));
|
||||
sin6.sin6_family = PF_INET6;
|
||||
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sin6.sin6_addr = *dst;
|
||||
/* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
|
||||
rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/
|
||||
if (!rt || (rt->rt_flags & RTF_HOST) == 0) {
|
||||
if (rt)
|
||||
RTFREE(rt);
|
||||
rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
|
||||
}
|
||||
|
||||
if (rt && (rt->rt_flags & RTF_HOST)
|
||||
&& !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
|
||||
if (mtu < IPV6_MMTU) {
|
||||
/* xxx */
|
||||
rt->rt_rmx.rmx_locks |= RTV_MTU;
|
||||
} else if (mtu < rt->rt_ifp->if_mtu &&
|
||||
rt->rt_rmx.rmx_mtu > mtu) {
|
||||
rt->rt_rmx.rmx_mtu = mtu;
|
||||
}
|
||||
}
|
||||
if (rt)
|
||||
RTFREE(rt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a Node Information Query
|
||||
*/
|
||||
@ -1156,8 +1326,16 @@ icmp6_rip6_input(mp, off)
|
||||
struct icmp6_hdr *icmp6;
|
||||
struct mbuf *opts = NULL;
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
/* this is assumed to be safe. */
|
||||
icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
|
||||
if (icmp6 == NULL) {
|
||||
/* m is already reclaimed */
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
bzero(&rip6src, sizeof(rip6src));
|
||||
rip6src.sin6_len = sizeof(struct sockaddr_in6);
|
||||
@ -1338,10 +1516,13 @@ icmp6_reflect(m, off)
|
||||
/*
|
||||
* If the incoming packet was addressed directly to us(i.e. unicast),
|
||||
* use dst as the src for the reply.
|
||||
* The IN6_IFF_NOTREADY case would be VERY rare, but is possible when
|
||||
* (for example) when we encounter an error while forwarding procedure
|
||||
* destined to a duplicated address of ours.
|
||||
*/
|
||||
for (ia = in6_ifaddr; ia; ia = ia->ia_next)
|
||||
if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
|
||||
(ia->ia6_flags & IN6_IFF_ANYCAST) == 0) {
|
||||
(ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
|
||||
src = &t;
|
||||
break;
|
||||
}
|
||||
@ -1355,9 +1536,11 @@ icmp6_reflect(m, off)
|
||||
|
||||
if (src == 0)
|
||||
/*
|
||||
* We have not multicast routing yet. So this case matches
|
||||
* to our multicast, our anycast or not to our unicast.
|
||||
* Select a source address which has the same scope.
|
||||
* This case matches to multicasts, our anycast, or unicasts
|
||||
* that we do not own. Select a source address which has the
|
||||
* same scope.
|
||||
* XXX: for (non link-local) multicast addresses, this might
|
||||
* not be a good choice.
|
||||
*/
|
||||
if ((ia = in6_ifawithscope(m->m_pkthdr.rcvif, &t)) != 0)
|
||||
src = &IA6_SIN6(ia)->sin6_addr;
|
||||
@ -1429,7 +1612,7 @@ icmp6_redirect_input(m, off)
|
||||
{
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct nd_redirect *nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
|
||||
struct nd_redirect *nd_rd;
|
||||
int icmp6len = ntohs(ip6->ip6_plen);
|
||||
char *lladdr = NULL;
|
||||
int lladdrlen = 0;
|
||||
@ -1439,8 +1622,8 @@ icmp6_redirect_input(m, off)
|
||||
int is_router;
|
||||
int is_onlink;
|
||||
struct in6_addr src6 = ip6->ip6_src;
|
||||
struct in6_addr redtgt6 = nd_rd->nd_rd_target;
|
||||
struct in6_addr reddst6 = nd_rd->nd_rd_dst;
|
||||
struct in6_addr redtgt6;
|
||||
struct in6_addr reddst6;
|
||||
union nd_opts ndopts;
|
||||
|
||||
if (!m || !ifp)
|
||||
@ -1448,28 +1631,41 @@ icmp6_redirect_input(m, off)
|
||||
|
||||
/* XXX if we are router, we don't update route by icmp6 redirect */
|
||||
if (ip6_forwarding)
|
||||
return;
|
||||
goto freeit;
|
||||
if (!icmp6_rediraccept)
|
||||
return;
|
||||
goto freeit;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
|
||||
redtgt6.s6_addr16[1] = htons(ifp->if_index);
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
|
||||
reddst6.s6_addr16[1] = htons(ifp->if_index);
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
||||
nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
|
||||
if (nd_rd == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
redtgt6 = nd_rd->nd_rd_target;
|
||||
reddst6 = nd_rd->nd_rd_dst;
|
||||
|
||||
/* validation */
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
|
||||
log(LOG_ERR,
|
||||
"ICMP6 redirect sent from %s rejected; "
|
||||
"must be from linklocal\n", ip6_sprintf(&src6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
if (ip6->ip6_hlim != 255) {
|
||||
log(LOG_ERR,
|
||||
"ICMP6 redirect sent from %s rejected; "
|
||||
"hlim=%d (must be 255)\n",
|
||||
ip6_sprintf(&src6), ip6->ip6_hlim);
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
{
|
||||
/* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
|
||||
@ -1480,8 +1676,7 @@ icmp6_redirect_input(m, off)
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
|
||||
rt = rtalloc1((struct sockaddr *)&sin6, 0
|
||||
);
|
||||
rt = rtalloc1((struct sockaddr *)&sin6, 0);
|
||||
if (rt) {
|
||||
gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
|
||||
if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
|
||||
@ -1492,14 +1687,14 @@ icmp6_redirect_input(m, off)
|
||||
ip6_sprintf(gw6),
|
||||
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
|
||||
RTFREE(rt);
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
} else {
|
||||
log(LOG_ERR,
|
||||
"ICMP6 redirect rejected; "
|
||||
"no route found for redirect dst: %s\n",
|
||||
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
RTFREE(rt);
|
||||
rt = NULL;
|
||||
@ -1509,7 +1704,7 @@ icmp6_redirect_input(m, off)
|
||||
"ICMP6 redirect rejected; "
|
||||
"redirect dst must be unicast: %s\n",
|
||||
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
is_router = is_onlink = 0;
|
||||
@ -1522,7 +1717,7 @@ icmp6_redirect_input(m, off)
|
||||
"ICMP6 redirect rejected; "
|
||||
"neither router case nor onlink case: %s\n",
|
||||
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
/* validation passed */
|
||||
|
||||
@ -1532,7 +1727,7 @@ icmp6_redirect_input(m, off)
|
||||
log(LOG_INFO, "icmp6_redirect_input: "
|
||||
"invalid ND option, rejected: %s\n",
|
||||
icmp6_redirect_diag(&src6, &reddst6, &redtgt6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
if (ndopts.nd_opts_tgt_lladdr) {
|
||||
@ -1610,6 +1805,9 @@ icmp6_redirect_input(m, off)
|
||||
key_sa_routechange((struct sockaddr *)&sdst);
|
||||
#endif
|
||||
}
|
||||
|
||||
freeit:
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1657,21 +1855,28 @@ icmp6_redirect_output(m0, rt)
|
||||
* we almost always ask for an mbuf cluster for simplicity.
|
||||
* (MHLEN < IPV6_MMTU is almost always true)
|
||||
*/
|
||||
#if IPV6_MMTU >= MCLBYTES
|
||||
# error assumption failed about IPV6_MMTU and MCLBYTES
|
||||
#endif
|
||||
MGETHDR(m, M_DONTWAIT, MT_HEADER);
|
||||
if (m && IPV6_MMTU >= MHLEN)
|
||||
MCLGET(m, M_DONTWAIT);
|
||||
if (!m)
|
||||
goto fail;
|
||||
if (MHLEN < IPV6_MMTU)
|
||||
MCLGET(m, M_DONTWAIT);
|
||||
maxlen = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
|
||||
maxlen = min(IPV6_MMTU, maxlen);
|
||||
/* just for safety */
|
||||
if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
|
||||
if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
|
||||
((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
/* get ip6 linklocal address for ifp(my outgoing interface). */
|
||||
struct in6_ifaddr *ia = in6ifa_ifpforlinklocal(ifp);
|
||||
if (ia == NULL)
|
||||
struct in6_ifaddr *ia;
|
||||
if ((ia = in6ifa_ifpforlinklocal(ifp,
|
||||
IN6_IFF_NOTREADY|
|
||||
IN6_IFF_ANYCAST)) == NULL)
|
||||
goto fail;
|
||||
ifp_ll6 = &ia->ia_addr.sin6_addr;
|
||||
}
|
||||
@ -1738,6 +1943,11 @@ icmp6_redirect_output(m0, rt)
|
||||
rt_router = nd6_lookup(router_ll6, 0, ifp);
|
||||
if (!rt_router)
|
||||
goto nolladdropt;
|
||||
len = sizeof(*nd_opt) + ifp->if_addrlen;
|
||||
len = (len + 7) & ~7; /*round by 8*/
|
||||
/* safety check */
|
||||
if (len + (p - (u_char *)ip6) > maxlen)
|
||||
goto nolladdropt;
|
||||
if (!(rt_router->rt_flags & RTF_GATEWAY) &&
|
||||
(rt_router->rt_flags & RTF_LLINFO) &&
|
||||
(rt_router->rt_gateway->sa_family == AF_LINK) &&
|
||||
@ -1745,12 +1955,10 @@ icmp6_redirect_output(m0, rt)
|
||||
sdl->sdl_alen) {
|
||||
nd_opt = (struct nd_opt_hdr *)p;
|
||||
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
|
||||
len = 2 + ifp->if_addrlen;
|
||||
len = (len + 7) & ~7; /*round by 8*/
|
||||
nd_opt->nd_opt_len = len >> 3;
|
||||
p += len;
|
||||
lladdr = (char *)(nd_opt + 1);
|
||||
bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
nolladdropt:;
|
||||
@ -1758,10 +1966,10 @@ nolladdropt:;
|
||||
m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
|
||||
|
||||
/* just to be safe */
|
||||
#ifdef M_DECRYPTED /*not openbsd*/
|
||||
if (m0->m_flags & M_DECRYPTED)
|
||||
goto noredhdropt;
|
||||
#endif
|
||||
if (p - (u_char *)ip6 > maxlen)
|
||||
goto noredhdropt;
|
||||
|
||||
{
|
||||
/* redirected header option */
|
||||
@ -1832,9 +2040,7 @@ nolladdropt:;
|
||||
m->m_next = m0;
|
||||
m->m_pkthdr.len = m->m_len + m0->m_len;
|
||||
}
|
||||
#ifdef M_DECRYPTED /*not openbsd*/
|
||||
noredhdropt:;
|
||||
#endif
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
|
||||
sip6->ip6_src.s6_addr16[1] = 0;
|
||||
@ -2087,8 +2293,6 @@ icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
|
||||
case ICMPV6CTL_ND6_USELOOPBACK:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&nd6_useloopback);
|
||||
case ICMPV6CTL_ND6_PROXYALL:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_proxyall);
|
||||
case ICMPV6CTL_NODEINFO:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6_nodeinfo);
|
||||
default:
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: in6.c,v 1.20 2000/02/25 05:13:05 itojun Exp $ */
|
||||
/* $NetBSD: in6.c,v 1.21 2000/02/26 08:39:19 itojun Exp $ */
|
||||
/* $KAME: in6.c,v 1.55 2000/02/25 00:32:23 itojun Exp $ */
|
||||
|
||||
/*
|
||||
@ -138,22 +138,6 @@ struct multi6_kludge {
|
||||
struct in6_multihead mk_head;
|
||||
};
|
||||
|
||||
/*
|
||||
* Determine whether an IP6 address is in a reserved set of addresses
|
||||
* that may not be forwarded, or whether datagrams to that destination
|
||||
* may be forwarded.
|
||||
*/
|
||||
int
|
||||
in6_canforward(src, dst)
|
||||
struct in6_addr *src, *dst;
|
||||
{
|
||||
if (IN6_IS_ADDR_LINKLOCAL(src) ||
|
||||
IN6_IS_ADDR_LINKLOCAL(dst) ||
|
||||
IN6_IS_ADDR_MULTICAST(dst))
|
||||
return(0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the loopback entry will be automatically generated.
|
||||
* if 0 returned, will not be automatically generated.
|
||||
@ -267,90 +251,6 @@ in6_ifremloop(struct ifaddr *ifa)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Subroutine for in6_ifaddproxy() and in6_ifremproxy().
|
||||
* This routine does actual work.
|
||||
* call in6_addmulti() when cmd == 1.
|
||||
* call in6_delmulti() when cmd == 2.
|
||||
*/
|
||||
static int
|
||||
in6_ifproxy_request(int cmd, struct in6_ifaddr *ia)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* If we have an IPv6 dstaddr on adding p2p interface,
|
||||
* join dstaddr's solicited multicast on necessary interface.
|
||||
*/
|
||||
if ((ia->ia_ifp->if_flags & IFF_POINTOPOINT) &&
|
||||
ia->ia_dstaddr.sin6_family == AF_INET6 &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
|
||||
struct in6_ifaddr *ia_lan;
|
||||
|
||||
/*
|
||||
* TODO: Join only on some specified interfaces by some
|
||||
* configuration.
|
||||
* Unsolicited Neighbor Advertisements will be also necessary.
|
||||
*
|
||||
* Now, join on interfaces which meets following.
|
||||
* -IFF_BROADCAST and IFF_MULTICAST
|
||||
* (NBMA is out of scope)
|
||||
* -the prefix value is same as p2p dstaddr
|
||||
*/
|
||||
for (ia_lan = in6_ifaddr; ia_lan; ia_lan = ia_lan->ia_next) {
|
||||
struct in6_addr llsol;
|
||||
|
||||
if ((ia_lan->ia_ifp->if_flags &
|
||||
(IFF_BROADCAST|IFF_MULTICAST)) !=
|
||||
(IFF_BROADCAST|IFF_MULTICAST))
|
||||
continue;
|
||||
if (!IN6_ARE_MASKED_ADDR_EQUAL(IA6_IN6(ia),
|
||||
IA6_IN6(ia_lan),
|
||||
IA6_MASKIN6(ia_lan)))
|
||||
continue;
|
||||
if (ia_lan->ia_ifp == ia->ia_ifp)
|
||||
continue;
|
||||
|
||||
/* init llsol */
|
||||
bzero(&llsol, sizeof(struct in6_addr));
|
||||
llsol.s6_addr16[0] = htons(0xff02);
|
||||
llsol.s6_addr16[1] = htons(ia_lan->ia_ifp->if_index);
|
||||
llsol.s6_addr32[1] = 0;
|
||||
llsol.s6_addr32[2] = htonl(1);
|
||||
llsol.s6_addr32[3] =
|
||||
ia->ia_dstaddr.sin6_addr.s6_addr32[3];
|
||||
llsol.s6_addr8[12] = 0xff;
|
||||
|
||||
if (cmd == 1)
|
||||
(void)in6_addmulti(&llsol,
|
||||
ia_lan->ia_ifp,
|
||||
&error);
|
||||
else if (cmd == 2) {
|
||||
struct in6_multi *in6m;
|
||||
|
||||
IN6_LOOKUP_MULTI(llsol,
|
||||
ia_lan->ia_ifp,
|
||||
in6m);
|
||||
if (in6m)
|
||||
in6_delmulti(in6m);
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
in6_ifaddproxy(struct in6_ifaddr *ia)
|
||||
{
|
||||
return(in6_ifproxy_request(1, ia));
|
||||
}
|
||||
|
||||
static void
|
||||
in6_ifremproxy(struct in6_ifaddr *ia)
|
||||
{
|
||||
in6_ifproxy_request(2, ia);
|
||||
}
|
||||
|
||||
int
|
||||
in6_ifindex2scopeid(idx)
|
||||
int idx;
|
||||
@ -837,14 +737,6 @@ in6_control(so, cmd, data, ifp, p)
|
||||
if (error == 0)
|
||||
error = error_local;
|
||||
}
|
||||
/* Join dstaddr's solicited multicast if necessary. */
|
||||
if (nd6_proxyall && hostIsNew) {
|
||||
int error_local;
|
||||
|
||||
error_local = in6_ifaddproxy(ia);
|
||||
if (error == 0)
|
||||
error = error_local;
|
||||
}
|
||||
|
||||
ia->ia6_flags = ifra->ifra_flags;
|
||||
ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /*safety*/
|
||||
@ -939,9 +831,6 @@ in6_purgeaddr(ifa, ifp)
|
||||
if (in6m)
|
||||
in6_delmulti(in6m);
|
||||
}
|
||||
/* Leave dstaddr's solicited multicast if necessary. */
|
||||
if (nd6_proxyall)
|
||||
in6_ifremproxy(ia);
|
||||
|
||||
TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
|
||||
IFAFREE(&ia->ia_ifa);
|
||||
@ -1086,7 +975,7 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p)
|
||||
* address. hostid points to the first link-local
|
||||
* address attached to the interface.
|
||||
*/
|
||||
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
|
||||
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
|
||||
if (!ifa)
|
||||
return EADDRNOTAVAIL;
|
||||
hostid = IFA_IN6(ifa);
|
||||
@ -1554,8 +1443,9 @@ in6_delmulti(in6m)
|
||||
* Find an IPv6 interface link-local address specific to an interface.
|
||||
*/
|
||||
struct in6_ifaddr *
|
||||
in6ifa_ifpforlinklocal(ifp)
|
||||
in6ifa_ifpforlinklocal(ifp, ignoreflags)
|
||||
struct ifnet *ifp;
|
||||
int ignoreflags;
|
||||
{
|
||||
register struct ifaddr *ifa;
|
||||
|
||||
@ -1565,8 +1455,12 @@ in6ifa_ifpforlinklocal(ifp)
|
||||
continue; /* just for safety */
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)))
|
||||
if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
|
||||
if ((((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
ignoreflags) != 0)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return((struct in6_ifaddr *)ifa);
|
||||
@ -1726,6 +1620,29 @@ struct in6_addr *addr;
|
||||
return IPV6_ADDR_SCOPE_GLOBAL;
|
||||
}
|
||||
|
||||
int
|
||||
in6_addr2scopeid(ifp, addr)
|
||||
struct ifnet *ifp; /* must not be NULL */
|
||||
struct in6_addr *addr; /* must not be NULL */
|
||||
{
|
||||
int scope = in6_addrscope(addr);
|
||||
|
||||
switch(scope) {
|
||||
case IPV6_ADDR_SCOPE_NODELOCAL:
|
||||
return(-1); /* XXX: is this an appropriate value? */
|
||||
|
||||
case IPV6_ADDR_SCOPE_LINKLOCAL:
|
||||
/* XXX: we do not distinguish between a link and an I/F. */
|
||||
return(ifp->if_index);
|
||||
|
||||
case IPV6_ADDR_SCOPE_SITELOCAL:
|
||||
return(0); /* XXX: invalid. */
|
||||
|
||||
default:
|
||||
return(0); /* XXX: treat as global. */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return length of part which dst and src are equal
|
||||
* hard coding...
|
||||
@ -1804,86 +1721,258 @@ in6_prefixlen2mask(maskp, len)
|
||||
/*
|
||||
* return the best address out of the same scope
|
||||
*/
|
||||
|
||||
struct in6_ifaddr *
|
||||
in6_ifawithscope(ifp, dst)
|
||||
register struct ifnet *ifp;
|
||||
in6_ifawithscope(oifp, dst)
|
||||
register struct ifnet *oifp;
|
||||
register struct in6_addr *dst;
|
||||
{
|
||||
int dst_scope = in6_addrscope(dst), blen = -1, tlen;
|
||||
int dst_scope = in6_addrscope(dst), src_scope, best_scope;
|
||||
int blen = -1;
|
||||
struct ifaddr *ifa;
|
||||
struct in6_ifaddr *besta = NULL, *ia;
|
||||
struct in6_ifaddr *dep[2]; /*last-resort: deprecated*/
|
||||
|
||||
dep[0] = dep[1] = NULL;
|
||||
struct ifnet *ifp;
|
||||
struct in6_ifaddr *ifa_best = NULL;
|
||||
|
||||
if (oifp == NULL) {
|
||||
printf("in6_ifawithscope: output interface is not specified\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We first look for addresses in the same scope.
|
||||
* If there is one, return it.
|
||||
* If two or more, return one which matches the dst longest.
|
||||
* If none, return one of global addresses assigned other ifs.
|
||||
* We search for all addresses on all interfaces from the beginning.
|
||||
* Comparing an interface with the outgoing interface will be done
|
||||
* only at the final stage of tiebreaking.
|
||||
*/
|
||||
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
|
||||
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
|
||||
for (ifp = ifnet; ifp; ifp = ifp->if_next)
|
||||
#else
|
||||
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
|
||||
#endif
|
||||
{
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
/*
|
||||
* We can never take an address that breaks the scope zone
|
||||
* of the destination.
|
||||
*/
|
||||
if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst))
|
||||
continue;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
|
||||
continue; /* XXX: is there any case to allow anycast? */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
|
||||
continue; /* don't use this interface */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
|
||||
continue;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
|
||||
if (ip6_use_deprecated)
|
||||
dep[0] = (struct in6_ifaddr *)ifa;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
|
||||
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
|
||||
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
|
||||
#else
|
||||
for (ifa = ifp->if_addrlist.tqh_first; ifa;
|
||||
ifa = ifa->ifa_list.tqe_next)
|
||||
#endif
|
||||
{
|
||||
int tlen = -1, dscopecmp, bscopecmp, matchcmp;
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
src_scope = in6_addrscope(IFA_IN6(ifa));
|
||||
|
||||
#ifdef ADDRSELECT_DEBUG /* should be removed after stabilization */
|
||||
dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
|
||||
printf("in6_ifawithscope: dst=%s bestaddr=%s, "
|
||||
"newaddr=%s, scope=%x, dcmp=%d, bcmp=%d, "
|
||||
"matchlen=%d, flgs=%x\n",
|
||||
ip6_sprintf(dst),
|
||||
ifa_best ? ip6_sprintf(&ifa_best->ia_addr.sin6_addr) : "none",
|
||||
ip6_sprintf(IFA_IN6(ifa)), src_scope,
|
||||
dscopecmp,
|
||||
ifa_best ? IN6_ARE_SCOPE_CMP(src_scope, best_scope) : -1,
|
||||
in6_matchlen(IFA_IN6(ifa), dst),
|
||||
((struct in6_ifaddr *)ifa)->ia6_flags);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call in6_matchlen() as few as possible
|
||||
* Don't use an address before completing DAD
|
||||
* nor a duplicated address.
|
||||
*/
|
||||
if (besta) {
|
||||
if (blen == -1)
|
||||
blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
|
||||
tlen = in6_matchlen(IFA_IN6(ifa), dst);
|
||||
if (tlen > blen) {
|
||||
blen = tlen;
|
||||
besta = (struct in6_ifaddr *)ifa;
|
||||
}
|
||||
} else
|
||||
besta = (struct in6_ifaddr *)ifa;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_NOTREADY)
|
||||
continue;
|
||||
|
||||
/* XXX: is there any case to allow anycasts? */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_ANYCAST)
|
||||
continue;
|
||||
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_DETACHED)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If this is the first address we find,
|
||||
* keep it anyway.
|
||||
*/
|
||||
if (ifa_best == NULL)
|
||||
goto replace;
|
||||
|
||||
/*
|
||||
* ifa_best is never NULL beyond this line except
|
||||
* within the block labeled "replace".
|
||||
*/
|
||||
|
||||
/*
|
||||
* If ifa_best has a smaller scope than dst and
|
||||
* the current address has a larger one than
|
||||
* (or equal to) dst, always replace ifa_best.
|
||||
* Also, if the current address has a smaller scope
|
||||
* than dst, ignore it unless ifa_best also has a
|
||||
* smaller scope.
|
||||
*/
|
||||
if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
|
||||
IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
|
||||
goto replace;
|
||||
if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
|
||||
IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* A deprecated address SHOULD NOT be used in new
|
||||
* communications if an alternate (non-deprecated)
|
||||
* address is available and has sufficient scope.
|
||||
* RFC 2462, Section 5.5.4.
|
||||
*/
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_DEPRECATED) {
|
||||
/*
|
||||
* Ignore any deprecated addresses if
|
||||
* specified by configuration.
|
||||
*/
|
||||
if (!ip6_use_deprecated)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we have already found a non-deprecated
|
||||
* candidate, just ignore deprecated addresses.
|
||||
*/
|
||||
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
|
||||
== 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A non-deprecated address is always preferred
|
||||
* to a deprecated one regardless of scopes and
|
||||
* address matching.
|
||||
*/
|
||||
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
|
||||
(((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_DEPRECATED) == 0)
|
||||
goto replace;
|
||||
|
||||
/*
|
||||
* At this point, we have two cases:
|
||||
* 1. we are looking at a non-deprecated address,
|
||||
* and ifa_best is also non-deprecated.
|
||||
* 2. we are looking at a deprecated address,
|
||||
* and ifa_best is also deprecated.
|
||||
* Also, we do not have to consider a case where
|
||||
* the scope of if_best is larger(smaller) than dst and
|
||||
* the scope of the current address is smaller(larger)
|
||||
* than dst. Such a case has already been covered.
|
||||
* Tiebreaking is done according to the following
|
||||
* items:
|
||||
* - the scope comparison between the address and
|
||||
* dst (dscopecmp)
|
||||
* - the scope comparison between the address and
|
||||
* ifa_best (bscopecmp)
|
||||
* - if the address match dst longer than ifa_best
|
||||
* (matchcmp)
|
||||
* - if the address is on the outgoing I/F (outI/F)
|
||||
*
|
||||
* Roughly speaking, the selection policy is
|
||||
* - the most important item is scope. The same scope
|
||||
* is best. Then search for a larger scope.
|
||||
* Smaller scopes are the last resort.
|
||||
* - A deprecated address is chosen only when we have
|
||||
* no address that has an enough scope, but is
|
||||
* prefered to any addresses of smaller scopes.
|
||||
* - Longest address match against dst is considered
|
||||
* only for addresses that has the same scope of dst.
|
||||
* - If there is no other reasons to choose one,
|
||||
* addresses on the outgoing I/F are preferred.
|
||||
*
|
||||
* The precise decision table is as follows:
|
||||
* dscopecmp bscopecmp matchcmp outI/F | replace?
|
||||
* !equal equal N/A Yes | Yes (1)
|
||||
* !equal equal N/A No | No (2)
|
||||
* larger larger N/A N/A | No (3)
|
||||
* larger smaller N/A N/A | Yes (4)
|
||||
* smaller larger N/A N/A | Yes (5)
|
||||
* smaller smaller N/A N/A | No (6)
|
||||
* equal smaller N/A N/A | Yes (7)
|
||||
* equal larger (already done)
|
||||
* equal equal larger N/A | Yes (8)
|
||||
* equal equal smaller N/A | No (9)
|
||||
* equal equal equal Yes | Yes (a)
|
||||
* eaual eqaul equal No | No (b)
|
||||
*/
|
||||
dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
|
||||
bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
|
||||
|
||||
if (dscopecmp && bscopecmp == 0) {
|
||||
if (oifp == ifp) /* (1) */
|
||||
goto replace;
|
||||
continue; /* (2) */
|
||||
}
|
||||
if (dscopecmp > 0) {
|
||||
if (bscopecmp > 0) /* (3) */
|
||||
continue;
|
||||
goto replace; /* (4) */
|
||||
}
|
||||
if (dscopecmp < 0) {
|
||||
if (bscopecmp > 0) /* (5) */
|
||||
goto replace;
|
||||
continue; /* (6) */
|
||||
}
|
||||
|
||||
/* now dscopecmp must be 0 */
|
||||
if (bscopecmp < 0)
|
||||
goto replace; /* (7) */
|
||||
|
||||
/*
|
||||
* At last both dscopecmp and bscopecmp must be 0.
|
||||
* We need address matching against dst for
|
||||
* tiebreaking.
|
||||
*/
|
||||
tlen = in6_matchlen(IFA_IN6(ifa), dst);
|
||||
matchcmp = tlen - blen;
|
||||
if (matchcmp > 0) /* (8) */
|
||||
goto replace;
|
||||
if (matchcmp < 0) /* (9) */
|
||||
continue;
|
||||
if (oifp == ifp) /* (a) */
|
||||
goto replace;
|
||||
continue; /* (b) */
|
||||
|
||||
replace:
|
||||
ifa_best = (struct in6_ifaddr *)ifa;
|
||||
blen = tlen >= 0 ? tlen :
|
||||
in6_matchlen(IFA_IN6(ifa), dst);
|
||||
best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
|
||||
}
|
||||
}
|
||||
if (besta)
|
||||
return besta;
|
||||
|
||||
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
|
||||
if (IPV6_ADDR_SCOPE_GLOBAL !=
|
||||
in6_addrscope(&(ia->ia_addr.sin6_addr)))
|
||||
continue;
|
||||
/* XXX: is there any case to allow anycast? */
|
||||
if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0)
|
||||
continue;
|
||||
if ((ia->ia6_flags & IN6_IFF_NOTREADY) != 0)
|
||||
continue;
|
||||
if ((ia->ia6_flags & IN6_IFF_DETACHED) != 0)
|
||||
continue;
|
||||
if ((ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) {
|
||||
if (ip6_use_deprecated)
|
||||
dep[1] = (struct in6_ifaddr *)ifa;
|
||||
continue;
|
||||
}
|
||||
return ia;
|
||||
/* count statistics for future improvements */
|
||||
if (ifa_best == NULL)
|
||||
ip6stat.ip6s_sources_none++;
|
||||
else {
|
||||
if (oifp == ifa_best->ia_ifp)
|
||||
ip6stat.ip6s_sources_sameif[best_scope]++;
|
||||
else
|
||||
ip6stat.ip6s_sources_otherif[best_scope]++;
|
||||
|
||||
if (best_scope == dst_scope)
|
||||
ip6stat.ip6s_sources_samescope[best_scope]++;
|
||||
else
|
||||
ip6stat.ip6s_sources_otherscope[best_scope]++;
|
||||
|
||||
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
|
||||
ip6stat.ip6s_sources_deprecated[best_scope]++;
|
||||
}
|
||||
|
||||
/* use the last-resort values, that are, deprecated addresses */
|
||||
if (dep[0])
|
||||
return dep[0];
|
||||
if (dep[1])
|
||||
return dep[1];
|
||||
|
||||
return NULL;
|
||||
return(ifa_best);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* $NetBSD: in6_var.h,v 1.11 2000/02/25 05:13:06 itojun Exp $ */
|
||||
/* $KAME: in6_var.h,v 1.28 2000/02/25 00:32:22 itojun Exp $ */
|
||||
/* $NetBSD: in6_var.h,v 1.12 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: in6_var.h,v 1.29 2000/02/25 05:20:58 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -570,10 +570,11 @@ void in6_savemkludge __P((struct in6_ifaddr *));
|
||||
void in6_setmaxmtu __P((void));
|
||||
void in6_restoremkludge __P((struct in6_ifaddr *, struct ifnet *));
|
||||
void in6_purgemkludge __P((struct ifnet *));
|
||||
struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *));
|
||||
struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *, int));
|
||||
struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *,
|
||||
struct in6_addr *));
|
||||
char *ip6_sprintf __P((struct in6_addr *));
|
||||
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 *p1, struct in6_addr *p2,
|
||||
int len));
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: ip6_forward.c,v 1.8 2000/02/06 12:49:45 itojun Exp $ */
|
||||
/* $NetBSD: ip6_forward.c,v 1.9 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: ip6_forward.c,v 1.28 2000/02/22 14:04:20 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -109,19 +110,17 @@ ip6_forward(m, srcrt)
|
||||
}
|
||||
#endif /*IPSEC_IPV6FWD*/
|
||||
|
||||
if (m->m_flags & (M_BCAST|M_MCAST) ||
|
||||
in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) {
|
||||
if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
|
||||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
||||
ip6stat.ip6s_cantforward++;
|
||||
ip6stat.ip6s_badscope++;
|
||||
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
|
||||
if (ip6_log_time + ip6_log_interval < time_second) {
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
ip6_log_time = time_second;
|
||||
strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr));
|
||||
log(LOG_DEBUG,
|
||||
"cannot forward "
|
||||
"from %s to %s nxt %d received on %s\n",
|
||||
addr, ip6_sprintf(&ip6->ip6_dst),
|
||||
ip6_sprintf(&ip6->ip6_src),
|
||||
ip6_sprintf(&ip6->ip6_dst),
|
||||
ip6->ip6_nxt,
|
||||
if_name(m->m_pkthdr.rcvif));
|
||||
}
|
||||
@ -324,6 +323,37 @@ ip6_forward(m, srcrt)
|
||||
}
|
||||
}
|
||||
rt = ip6_forward_rt.ro_rt;
|
||||
|
||||
/*
|
||||
* Scope check: if a packet can't be delivered to its destination
|
||||
* for the reason that the destination is beyond the scope of the
|
||||
* source address, discard the packet and return an icmp6 destination
|
||||
* unreachable error with Code 2 (beyond scope of source address).
|
||||
* [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
|
||||
*/
|
||||
if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
|
||||
in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
|
||||
ip6stat.ip6s_cantforward++;
|
||||
ip6stat.ip6s_badscope++;
|
||||
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
|
||||
|
||||
if (ip6_log_time + ip6_log_interval < time_second) {
|
||||
ip6_log_time = time_second;
|
||||
log(LOG_DEBUG,
|
||||
"cannot forward "
|
||||
"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
|
||||
ip6_sprintf(&ip6->ip6_src),
|
||||
ip6_sprintf(&ip6->ip6_dst),
|
||||
ip6->ip6_nxt,
|
||||
if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
|
||||
}
|
||||
if (mcopy)
|
||||
icmp6_error(mcopy, ICMP6_DST_UNREACH,
|
||||
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
|
||||
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
|
||||
if (mcopy) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: ip6_var.h,v 1.9 2000/02/03 18:13:02 itojun Exp $ */
|
||||
/* $NetBSD: ip6_var.h,v 1.10 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: ip6_var.h,v 1.27 2000/02/22 14:04:22 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -170,9 +171,43 @@ struct ip6stat {
|
||||
u_quad_t ip6s_nogif; /* no match gif found */
|
||||
u_quad_t ip6s_toomanyhdr; /* discarded due to too many headers */
|
||||
/* XXX the following two items are not really AF_INET6 thing */
|
||||
u_quad_t ip6s_exthdrget; /* # of calls to IP6_EXTHDR_GET */
|
||||
u_quad_t ip6s_exthdrget0; /* # of calls to IP6_EXTHDR_GET0 */
|
||||
u_quad_t ip6s_pulldown; /* # of calls to m_pulldown */
|
||||
u_quad_t ip6s_pulldown_copy; /* # of mbuf copies in m_pulldown */
|
||||
u_quad_t ip6s_pulldown_alloc; /* # of mbuf allocs in m_pulldown */
|
||||
u_quad_t ip6s_pullup; /* # of calls to m_pullup */
|
||||
u_quad_t ip6s_pullup_copy; /* # of possible m_pullup copies */
|
||||
u_quad_t ip6s_pullup_alloc; /* # of possible m_pullup mallocs */
|
||||
u_quad_t ip6s_pullup_fail; /* # of possible m_pullup failures */
|
||||
u_quad_t ip6s_pullup2; /* # of calls to m_pullup2 */
|
||||
u_quad_t ip6s_pullup2_copy; /* # of possible m_pullup2 copies */
|
||||
u_quad_t ip6s_pullup2_alloc; /* # of possible m_pullup2 mallocs */
|
||||
u_quad_t ip6s_pullup2_fail; /* # of possible m_pullup2 failures */
|
||||
|
||||
/*
|
||||
* statistics for improvement of the source address selection
|
||||
* algorithm:
|
||||
* XXX: hardcoded 16 = # of ip6 multicast scope types + 1
|
||||
*/
|
||||
/* number of times that address selection fails */
|
||||
u_quad_t ip6s_sources_none;
|
||||
/* number of times that an address on the outgoing I/F is chosen */
|
||||
u_quad_t ip6s_sources_sameif[16];
|
||||
/* number of times that an address on a non-outgoing I/F is chosen */
|
||||
u_quad_t ip6s_sources_otherif[16];
|
||||
/*
|
||||
* number of times that an address that has the same scope
|
||||
* from the destination is chosen.
|
||||
*/
|
||||
u_quad_t ip6s_sources_samescope[16];
|
||||
/*
|
||||
* number of times that an address that has a different scope
|
||||
* from the destination is chosen.
|
||||
*/
|
||||
u_quad_t ip6s_sources_otherscope[16];
|
||||
/* number of times that an deprecated address is chosen */
|
||||
u_quad_t ip6s_sources_deprecated[16];
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: mld6.c,v 1.10 2000/02/06 12:49:47 itojun Exp $ */
|
||||
/* $NetBSD: mld6.c,v 1.11 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: mld6.c,v 1.16 2000/02/22 14:04:27 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 WIDE Project.
|
||||
@ -119,7 +120,7 @@ mld6_init()
|
||||
mld6_timers_are_running = 0;
|
||||
|
||||
/* ip6h_nxt will be fill in later */
|
||||
hbh->ip6h_len = 0; /* (8 >> 3) - 1*/
|
||||
hbh->ip6h_len = 0; /* (8 >> 3) - 1 */
|
||||
|
||||
/* XXX: grotty hard coding... */
|
||||
hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */
|
||||
@ -140,7 +141,7 @@ mld6_start_listening(in6m)
|
||||
int s = splsoftnet();
|
||||
|
||||
/*
|
||||
* (draft-ietf-ipngwg-mld, page 10)
|
||||
* RFC2710 page 10:
|
||||
* The node never sends a Report or Done for the link-scope all-nodes
|
||||
* address.
|
||||
* MLD messages are never sent for multicast addresses whose scope is 0
|
||||
@ -184,7 +185,7 @@ mld6_input(m, off)
|
||||
int off;
|
||||
{
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct mld6_hdr *mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off);
|
||||
struct mld6_hdr *mldh;
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct in6_multi *in6m;
|
||||
struct in6_ifaddr *ia;
|
||||
@ -196,13 +197,25 @@ mld6_input(m, off)
|
||||
"mld6_input: src %s is not link-local\n",
|
||||
ip6_sprintf(&ip6->ip6_src));
|
||||
/*
|
||||
* spec(draft-ietf-ipngwg-mld) does not explicitly
|
||||
* spec (RFC2710) does not explicitly
|
||||
* specify to discard the packet from a non link-local
|
||||
* source address. But we believe it's expected to do so.
|
||||
*/
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),);
|
||||
mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh));
|
||||
if (mldh == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In the MLD6 specification, there are 3 states and a flag.
|
||||
*
|
||||
@ -227,25 +240,25 @@ mld6_input(m, off)
|
||||
htons(ifp->if_index); /* XXX */
|
||||
|
||||
/*
|
||||
* - Start the timers in all of our membership records
|
||||
* that the query applies to for the interface on
|
||||
* which the query arrived excl. those that belong
|
||||
* to the "all-nodes" group (ff02::1).
|
||||
* - Restart any timer that is already running but has
|
||||
* A value longer than the requested timeout.
|
||||
* - Use the value specified in the query message as
|
||||
* the maximum timeout.
|
||||
*/
|
||||
* - Start the timers in all of our membership records
|
||||
* that the query applies to for the interface on
|
||||
* which the query arrived excl. those that belong
|
||||
* to the "all-nodes" group (ff02::1).
|
||||
* - Restart any timer that is already running but has
|
||||
* A value longer than the requested timeout.
|
||||
* - Use the value specified in the query message as
|
||||
* the maximum timeout.
|
||||
*/
|
||||
IFP_TO_IA6(ifp, ia);
|
||||
if (ia == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* XXX: System timer resolution is too low to handle Max
|
||||
* Response Delay, so set 1 to the internal timer even if
|
||||
* the calculated value equals to zero when Max Response
|
||||
* Delay is positive.
|
||||
*/
|
||||
* XXX: System timer resolution is too low to handle Max
|
||||
* Response Delay, so set 1 to the internal timer even if
|
||||
* the calculated value equals to zero when Max Response
|
||||
* Delay is positive.
|
||||
*/
|
||||
timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE;
|
||||
if (timer == 0 && mldh->mld6_maxdelay)
|
||||
timer = 1;
|
||||
@ -287,14 +300,14 @@ mld6_input(m, off)
|
||||
break;
|
||||
case MLD6_LISTENER_REPORT:
|
||||
/*
|
||||
* For fast leave to work, we have to know that we are the
|
||||
* last person to send a report for this group. Reports
|
||||
* can potentially get looped back if we are a multicast
|
||||
* router, so discard reports sourced by me.
|
||||
* Note that it is impossible to check IFF_LOOPBACK flag of
|
||||
* ifp for this purpose, since ip6_mloopback pass the physical
|
||||
* interface to looutput.
|
||||
*/
|
||||
* For fast leave to work, we have to know that we are the
|
||||
* last person to send a report for this group. Reports
|
||||
* can potentially get looped back if we are a multicast
|
||||
* router, so discard reports sourced by me.
|
||||
* Note that it is impossible to check IFF_LOOPBACK flag of
|
||||
* ifp for this purpose, since ip6_mloopback pass the physical
|
||||
* interface to looutput.
|
||||
*/
|
||||
if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
|
||||
break;
|
||||
|
||||
@ -305,9 +318,9 @@ mld6_input(m, off)
|
||||
mldh->mld6_addr.s6_addr16[1] =
|
||||
htons(ifp->if_index); /* XXX */
|
||||
/*
|
||||
* If we belong to the group being reported, stop
|
||||
* our timer for that group.
|
||||
*/
|
||||
* If we belong to the group being reported, stop
|
||||
* our timer for that group.
|
||||
*/
|
||||
IN6_LOOKUP_MULTI(mldh->mld6_addr, ifp, in6m);
|
||||
if (in6m) {
|
||||
in6m->in6m_timer = 0; /* transit to idle state */
|
||||
@ -321,6 +334,8 @@ mld6_input(m, off)
|
||||
log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type);
|
||||
break;
|
||||
}
|
||||
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
void
|
||||
@ -372,7 +387,8 @@ mld6_sendpkt(in6m, type, dst)
|
||||
* At first, find a link local address on the outgoing interface
|
||||
* to use as the source address of the MLD packet.
|
||||
*/
|
||||
if ((ia = in6ifa_ifpforlinklocal(ifp)) == NULL)
|
||||
if ((ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST))
|
||||
== NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: nd6.c,v 1.17 2000/02/06 12:49:47 itojun Exp $ */
|
||||
/* $NetBSD: nd6.c,v 1.18 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: nd6.c,v 1.41 2000/02/24 16:34:50 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -45,6 +46,7 @@
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syslog.h>
|
||||
@ -84,7 +86,6 @@ int nd6_delay = 5; /* delay first probe time 5 second */
|
||||
int nd6_umaxtries = 3; /* maximum unicast query */
|
||||
int nd6_mmaxtries = 3; /* maximum multicast query */
|
||||
int nd6_useloopback = 1; /* use loopback interface for local traffic */
|
||||
int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */
|
||||
|
||||
/* preventing too many loops in ND option parsing */
|
||||
int nd6_maxndopt = 10; /* max # of ND options allowed */
|
||||
@ -431,9 +432,8 @@ nd6_timer(ignored_arg)
|
||||
}
|
||||
break;
|
||||
case ND6_LLINFO_REACHABLE:
|
||||
if (ln->ln_expire) {
|
||||
if (ln->ln_expire)
|
||||
ln->ln_state = ND6_LLINFO_STALE;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* ND6_LLINFO_STALE state requires nothing for timer
|
||||
@ -578,7 +578,7 @@ nd6_purge(ifp)
|
||||
* Nuke neighbor cache entries for the ifp.
|
||||
* Note that rt->rt_ifp may not be the same as ifp,
|
||||
* due to KAME goto ours hack. See RTM_RESOLVE case in
|
||||
* nd6_rtrequest(), and ip6_input()).
|
||||
* nd6_rtrequest(), and ip6_input().
|
||||
*/
|
||||
ln = llinfo_nd6.ln_next;
|
||||
while (ln && ln != &llinfo_nd6) {
|
||||
@ -597,7 +597,8 @@ nd6_purge(ifp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface route will be retained by nd6_free(). Nuke it.
|
||||
* Neighbor cache entry for interface route will be retained
|
||||
* with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it.
|
||||
*/
|
||||
ln = llinfo_nd6.ln_next;
|
||||
while (ln && ln != &llinfo_nd6) {
|
||||
@ -768,9 +769,19 @@ nd6_free(rt)
|
||||
struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
|
||||
struct nd_defrouter *dr;
|
||||
|
||||
/*
|
||||
* Clear all destination cache entries for the neighbor.
|
||||
* XXX: is it better to restrict this to hosts?
|
||||
*/
|
||||
pfctlinput(PRC_HOSTDEAD, rt_key(rt));
|
||||
|
||||
if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */
|
||||
int s;
|
||||
#ifdef __NetBSD__
|
||||
s = splsoftnet();
|
||||
#else
|
||||
s = splnet();
|
||||
#endif
|
||||
dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
|
||||
rt->rt_ifp);
|
||||
if (ln->ln_router || dr) {
|
||||
@ -993,7 +1004,7 @@ nd6_rtrequest(req, rt, sa)
|
||||
* SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
|
||||
* rt->rt_flags |= RTF_CLONING;
|
||||
*/
|
||||
if (rt->rt_flags & RTF_CLONING || rt->rt_flags & RTF_LLINFO) {
|
||||
if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) {
|
||||
/*
|
||||
* Case 1: This route should come from
|
||||
* a route to interface. RTF_LLINFO flag is set
|
||||
@ -1020,17 +1031,37 @@ nd6_rtrequest(req, rt, sa)
|
||||
if (rt->rt_flags & RTF_CLONING)
|
||||
break;
|
||||
}
|
||||
/* Announce a new entry if requested. */
|
||||
/*
|
||||
* In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here.
|
||||
* We don't do that here since llinfo is not ready yet.
|
||||
*
|
||||
* There are also couple of other things to be discussed:
|
||||
* - unsolicited NA code needs improvement beforehand
|
||||
* - RFC2461 says we MAY send multicast unsolicited NA
|
||||
* (7.2.6 paragraph 4), however, it also says that we
|
||||
* SHOULD provide a mechanism to prevent multicast NA storm.
|
||||
* we don't have anything like it right now.
|
||||
* note that the mechanism need a mutual agreement
|
||||
* between proxies, which means that we need to implement
|
||||
* a new protocol, or new kludge.
|
||||
* - from RFC2461 6.2.4, host MUST NOT send unsolicited NA.
|
||||
* we need to check ip6forwarding before sending it.
|
||||
* (or should we allow proxy ND configuration only for
|
||||
* routers? there's no mention about proxy ND from hosts)
|
||||
*/
|
||||
#if 0
|
||||
/* XXX it does not work */
|
||||
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);
|
||||
&SIN6(rt_key(rt))->sin6_addr,
|
||||
&SIN6(rt_key(rt))->sin6_addr,
|
||||
ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
|
||||
1, NULL);
|
||||
#endif
|
||||
/* FALLTHROUGH */
|
||||
case RTM_RESOLVE:
|
||||
if (gate->sa_family != AF_LINK ||
|
||||
gate->sa_len < sizeof(null_sdl)) {
|
||||
gate->sa_len < sizeof(null_sdl)) {
|
||||
log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n");
|
||||
break;
|
||||
}
|
||||
@ -1104,12 +1135,50 @@ nd6_rtrequest(req, rt, sa)
|
||||
rt->rt_ifa = ifa;
|
||||
}
|
||||
}
|
||||
} else if (rt->rt_flags & RTF_ANNOUNCE) {
|
||||
ln->ln_expire = 0;
|
||||
ln->ln_state = ND6_LLINFO_REACHABLE;
|
||||
|
||||
/* join solicited node multicast for proxy ND */
|
||||
if (ifp->if_flags & IFF_MULTICAST) {
|
||||
struct in6_addr llsol;
|
||||
int error;
|
||||
|
||||
llsol = SIN6(rt_key(rt))->sin6_addr;
|
||||
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_addr8[12] = 0xff;
|
||||
|
||||
(void)in6_addmulti(&llsol, ifp, &error);
|
||||
if (error)
|
||||
printf(
|
||||
"nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RTM_DELETE:
|
||||
if (!ln)
|
||||
break;
|
||||
/* leave from solicited node multicast for proxy ND */
|
||||
if ((rt->rt_flags & RTF_ANNOUNCE) != 0 &&
|
||||
(ifp->if_flags & IFF_MULTICAST) != 0) {
|
||||
struct in6_addr llsol;
|
||||
struct in6_multi *in6m;
|
||||
|
||||
llsol = SIN6(rt_key(rt))->sin6_addr;
|
||||
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_addr8[12] = 0xff;
|
||||
|
||||
IN6_LOOKUP_MULTI(llsol, ifp, in6m);
|
||||
if (in6m)
|
||||
in6_delmulti(in6m);
|
||||
}
|
||||
nd6_inuse--;
|
||||
ln->ln_next->ln_prev = ln->ln_prev;
|
||||
ln->ln_prev->ln_next = ln->ln_next;
|
||||
@ -1163,7 +1232,7 @@ nd6_p2p_rtrequest(req, rt, sa)
|
||||
&SIN6(rt_key(rt))->sin6_addr,
|
||||
&SIN6(rt_key(rt))->sin6_addr,
|
||||
ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,
|
||||
1);
|
||||
1, NULL);
|
||||
/* FALLTHROUGH */
|
||||
case RTM_RESOLVE:
|
||||
/*
|
||||
@ -1225,6 +1294,11 @@ nd6_ioctl(cmd, data, ifp)
|
||||
splx(s);
|
||||
break;
|
||||
case SIOCGPRLST_IN6:
|
||||
/*
|
||||
* 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));
|
||||
s = splsoftnet();
|
||||
pr = nd_prefix.lh_first;
|
||||
@ -1262,11 +1336,11 @@ nd6_ioctl(cmd, data, ifp)
|
||||
pfr = pfr->pfr_next;
|
||||
}
|
||||
prl->prefix[i].advrtrs = j;
|
||||
prl->prefix[i].origin = PR_ORIG_RA;
|
||||
|
||||
i++;
|
||||
pr = pr->ndpr_next;
|
||||
}
|
||||
splx(s);
|
||||
{
|
||||
struct rr_prefix *rpp;
|
||||
|
||||
@ -1282,9 +1356,11 @@ nd6_ioctl(cmd, data, ifp)
|
||||
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;
|
||||
case SIOCGIFINFO_IN6:
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: nd6.h,v 1.8 2000/02/04 14:34:28 itojun Exp $ */
|
||||
/* $NetBSD: nd6.h,v 1.9 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: nd6.h,v 1.16 2000/02/24 16:34:51 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -32,6 +33,11 @@
|
||||
#ifndef _NETINET6_ND6_H_
|
||||
#define _NETINET6_ND6_H_
|
||||
|
||||
/* see net/route.h, or net/if_inarp.h */
|
||||
#ifndef RTF_ANNOUNCE
|
||||
#define RTF_ANNOUNCE RTF_PROTO2
|
||||
#endif
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
struct llinfo_nd6 {
|
||||
@ -94,6 +100,7 @@ struct in6_prlist {
|
||||
struct in6_addr prefix;
|
||||
struct prf_ra raflags;
|
||||
u_char prefixlen;
|
||||
u_char origin;
|
||||
u_long vltime;
|
||||
u_long pltime;
|
||||
u_long expire;
|
||||
@ -220,7 +227,6 @@ extern int nd6_delay;
|
||||
extern int nd6_umaxtries;
|
||||
extern int nd6_mmaxtries;
|
||||
extern int nd6_useloopback;
|
||||
extern int nd6_proxyall;
|
||||
extern struct llinfo_nd6 llinfo_nd6;
|
||||
extern struct nd_ifinfo *nd_ifinfo;
|
||||
extern struct nd_drhead nd_defrouter;
|
||||
@ -284,7 +290,7 @@ int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *,
|
||||
/* nd6_nbr.c */
|
||||
void nd6_na_input __P((struct mbuf *, int, int));
|
||||
void nd6_na_output __P((struct ifnet *, struct in6_addr *,
|
||||
struct in6_addr *, u_long, int));
|
||||
struct in6_addr *, u_long, int, struct sockaddr *));
|
||||
void nd6_ns_input __P((struct mbuf *, int, int));
|
||||
void nd6_ns_output __P((struct ifnet *, struct in6_addr *,
|
||||
struct in6_addr *, struct llinfo_nd6 *, int));
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: nd6_nbr.c,v 1.15 2000/02/07 05:42:28 itojun Exp $ */
|
||||
/* $NetBSD: nd6_nbr.c,v 1.16 2000/02/26 08:39:20 itojun Exp $ */
|
||||
/* $KAME: nd6_nbr.c,v 1.28 2000/02/26 06:53:11 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -77,8 +78,6 @@ static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */
|
||||
*
|
||||
* Based on RFC 2461
|
||||
* Based on RFC 2462 (duplicated address detection)
|
||||
*
|
||||
* XXX proxy advertisement
|
||||
*/
|
||||
void
|
||||
nd6_ns_input(m, off, icmp6len)
|
||||
@ -87,11 +86,10 @@ nd6_ns_input(m, off, icmp6len)
|
||||
{
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct nd_neighbor_solicit *nd_ns
|
||||
= (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
|
||||
struct nd_neighbor_solicit *nd_ns;
|
||||
struct in6_addr saddr6 = ip6->ip6_src;
|
||||
struct in6_addr daddr6 = ip6->ip6_dst;
|
||||
struct in6_addr taddr6 = nd_ns->nd_ns_target;
|
||||
struct in6_addr taddr6;
|
||||
struct in6_addr myaddr6;
|
||||
char *lladdr = NULL;
|
||||
struct ifaddr *ifa;
|
||||
@ -99,11 +97,12 @@ nd6_ns_input(m, off, icmp6len)
|
||||
int anycast = 0, proxy = 0, tentative = 0;
|
||||
int tlladdr;
|
||||
union nd_opts ndopts;
|
||||
struct sockaddr_dl *proxydl = NULL;
|
||||
|
||||
if (ip6->ip6_hlim != 255) {
|
||||
log(LOG_ERR,
|
||||
"nd6_ns_input: invalid hlim %d\n", ip6->ip6_hlim);
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
|
||||
@ -121,6 +120,18 @@ nd6_ns_input(m, off, icmp6len)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
||||
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
|
||||
if (nd_ns == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
taddr6 = nd_ns->nd_ns_target;
|
||||
|
||||
if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
|
||||
log(LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n");
|
||||
goto bad;
|
||||
@ -178,7 +189,7 @@ nd6_ns_input(m, off, icmp6len)
|
||||
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
|
||||
|
||||
/* (2) check. */
|
||||
if (!ifa && nd6_proxyall) {
|
||||
if (!ifa) {
|
||||
struct rtentry *rt;
|
||||
struct sockaddr_in6 tsin6;
|
||||
|
||||
@ -187,17 +198,25 @@ nd6_ns_input(m, off, icmp6len)
|
||||
tsin6.sin6_family = AF_INET6;
|
||||
tsin6.sin6_addr = taddr6;
|
||||
|
||||
rt = rtalloc1((struct sockaddr *)&tsin6, 0);
|
||||
if (rt && rt->rt_ifp != ifp) {
|
||||
rt = rtalloc1((struct sockaddr *)&tsin6, 0
|
||||
#ifdef __FreeBSD__
|
||||
, 0
|
||||
#endif /* __FreeBSD__ */
|
||||
);
|
||||
if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
|
||||
rt->rt_gateway->sa_family == AF_LINK) {
|
||||
/*
|
||||
* search link local addr for ifp, and use it for
|
||||
* proxy NA.
|
||||
* proxy NDP for single entry
|
||||
*/
|
||||
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
|
||||
if (ifa)
|
||||
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
|
||||
IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
|
||||
if (ifa) {
|
||||
proxy = 1;
|
||||
proxydl = SDL(rt->rt_gateway);
|
||||
}
|
||||
}
|
||||
rtfree(rt);
|
||||
if (rt)
|
||||
rtfree(rt);
|
||||
}
|
||||
if (!ifa) {
|
||||
/*
|
||||
@ -205,13 +224,13 @@ nd6_ns_input(m, off, icmp6len)
|
||||
* assigned for us. We MUST silently ignore it.
|
||||
* See RFC2461 7.2.3.
|
||||
*/
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
myaddr6 = *IFA_IN6(ifa);
|
||||
anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
|
||||
tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
|
||||
return;
|
||||
goto freeit;
|
||||
|
||||
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
|
||||
log(LOG_INFO,
|
||||
@ -224,7 +243,7 @@ nd6_ns_input(m, off, icmp6len)
|
||||
log(LOG_INFO,
|
||||
"nd6_ns_input: duplicate IP6 address %s\n",
|
||||
ip6_sprintf(&saddr6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -250,7 +269,7 @@ nd6_ns_input(m, off, icmp6len)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
|
||||
nd6_dad_ns_input(ifa);
|
||||
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -268,8 +287,8 @@ nd6_ns_input(m, off, icmp6len)
|
||||
((anycast || proxy || !tlladdr)
|
||||
? 0 : ND_NA_FLAG_OVERRIDE)
|
||||
| (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
|
||||
tlladdr);
|
||||
return;
|
||||
tlladdr, (struct sockaddr *)proxydl);
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
|
||||
@ -278,14 +297,16 @@ nd6_ns_input(m, off, icmp6len)
|
||||
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE)
|
||||
| (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0)
|
||||
| ND_NA_FLAG_SOLICITED,
|
||||
tlladdr);
|
||||
tlladdr, (struct sockaddr *)proxydl);
|
||||
freeit:
|
||||
m_freem(m);
|
||||
return;
|
||||
|
||||
bad:
|
||||
log(LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6));
|
||||
log(LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6));
|
||||
log(LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6));
|
||||
return;
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -485,6 +506,10 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
|
||||
*
|
||||
* Based on RFC 2461
|
||||
* Based on RFC 2462 (duplicated address detection)
|
||||
*
|
||||
* the following items are not implemented yet:
|
||||
* - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
|
||||
* - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
|
||||
*/
|
||||
void
|
||||
nd6_na_input(m, off, icmp6len)
|
||||
@ -493,17 +518,16 @@ nd6_na_input(m, off, icmp6len)
|
||||
{
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct nd_neighbor_advert *nd_na
|
||||
= (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
|
||||
struct nd_neighbor_advert *nd_na;
|
||||
#if 0
|
||||
struct in6_addr saddr6 = ip6->ip6_src;
|
||||
#endif
|
||||
struct in6_addr daddr6 = ip6->ip6_dst;
|
||||
struct in6_addr taddr6 = nd_na->nd_na_target;
|
||||
int flags = nd_na->nd_na_flags_reserved;
|
||||
int is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
|
||||
int is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
|
||||
int is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
|
||||
struct in6_addr taddr6;
|
||||
int flags;
|
||||
int is_router;
|
||||
int is_solicited;
|
||||
int is_override;
|
||||
char *lladdr = NULL;
|
||||
int lladdrlen = 0;
|
||||
struct ifaddr *ifa;
|
||||
@ -515,8 +539,24 @@ nd6_na_input(m, off, icmp6len)
|
||||
if (ip6->ip6_hlim != 255) {
|
||||
log(LOG_ERR,
|
||||
"nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim);
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
||||
nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
|
||||
if (nd_na == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
taddr6 = nd_na->nd_na_target;
|
||||
flags = nd_na->nd_na_flags_reserved;
|
||||
is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
|
||||
is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
|
||||
is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
|
||||
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
|
||||
taddr6.s6_addr16[1] = htons(ifp->if_index);
|
||||
@ -525,20 +565,20 @@ nd6_na_input(m, off, icmp6len)
|
||||
log(LOG_ERR,
|
||||
"nd6_na_input: invalid target address %s\n",
|
||||
ip6_sprintf(&taddr6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
if (IN6_IS_ADDR_MULTICAST(&daddr6))
|
||||
if (is_solicited) {
|
||||
log(LOG_ERR,
|
||||
"nd6_na_input: a solicited adv is multicasted\n");
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
icmp6len -= sizeof(*nd_na);
|
||||
nd6_option_init(nd_na + 1, icmp6len, &ndopts);
|
||||
if (nd6_options(&ndopts) < 0) {
|
||||
log(LOG_INFO, "nd6_na_input: invalid ND option, ignored\n");
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
if (ndopts.nd_opts_tgt_lladdr) {
|
||||
@ -560,7 +600,7 @@ nd6_na_input(m, off, icmp6len)
|
||||
if (ifa
|
||||
&& (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
|
||||
nd6_dad_na_input(ifa);
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
/* Just for safety, maybe unnecessery. */
|
||||
@ -568,7 +608,7 @@ nd6_na_input(m, off, icmp6len)
|
||||
log(LOG_ERR,
|
||||
"nd6_na_input: duplicate IP6 address %s\n",
|
||||
ip6_sprintf(&taddr6));
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
|
||||
@ -585,7 +625,7 @@ nd6_na_input(m, off, icmp6len)
|
||||
if ((rt == NULL) ||
|
||||
((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
|
||||
((sdl = SDL(rt->rt_gateway)) == NULL))
|
||||
return;
|
||||
goto freeit;
|
||||
|
||||
if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
|
||||
/*
|
||||
@ -593,7 +633,7 @@ nd6_na_input(m, off, icmp6len)
|
||||
* discard the packet.
|
||||
*/
|
||||
if (ifp->if_addrlen && !lladdr)
|
||||
return;
|
||||
goto freeit;
|
||||
|
||||
/*
|
||||
* Record link-layer address, and update the state.
|
||||
@ -652,7 +692,7 @@ nd6_na_input(m, off, icmp6len)
|
||||
*/
|
||||
if (ln->ln_state == ND6_LLINFO_REACHABLE)
|
||||
ln->ln_state = ND6_LLINFO_STALE;
|
||||
return;
|
||||
goto freeit;
|
||||
} else if (is_override /* (2a) */
|
||||
|| (!is_override && (lladdr && !llchange)) /* (2b) */
|
||||
|| !lladdr) { /* (2c) */
|
||||
@ -721,6 +761,9 @@ nd6_na_input(m, off, icmp6len)
|
||||
#endif
|
||||
ln->ln_hold = 0;
|
||||
}
|
||||
|
||||
freeit:
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -728,16 +771,17 @@ nd6_na_input(m, off, icmp6len)
|
||||
*
|
||||
* Based on RFC 2461
|
||||
*
|
||||
* XXX NA delay for anycast address is not implemented yet
|
||||
* (RFC 2461 7.2.7)
|
||||
* XXX proxy advertisement?
|
||||
* the following items are not implemented yet:
|
||||
* - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
|
||||
* - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
|
||||
*/
|
||||
void
|
||||
nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
|
||||
nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
|
||||
struct ifnet *ifp;
|
||||
struct in6_addr *daddr6, *taddr6;
|
||||
u_long flags;
|
||||
int tlladdr; /* 1 if include target link-layer address */
|
||||
int tlladdr; /* 1 if include target link-layer address */
|
||||
struct sockaddr *sdl0; /* sockaddr_dl (= proxy NA) or NULL */
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct ip6_hdr *ip6;
|
||||
@ -822,7 +866,23 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
|
||||
* Basically, if NS packet is sent to unicast/anycast addr,
|
||||
* target lladdr option SHOULD NOT be included.
|
||||
*/
|
||||
if (tlladdr && (mac = nd6_ifptomac(ifp))) {
|
||||
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
|
||||
* my address) use lladdr configured for the interface.
|
||||
*/
|
||||
if (sdl0 == NULL)
|
||||
mac = nd6_ifptomac(ifp);
|
||||
else if (sdl0->sa_family == AF_LINK) {
|
||||
struct sockaddr_dl *sdl;
|
||||
sdl = (struct sockaddr_dl *)sdl0;
|
||||
if (sdl->sdl_alen == ifp->if_addrlen)
|
||||
mac = LLADDR(sdl);
|
||||
}
|
||||
}
|
||||
if (tlladdr && mac) {
|
||||
int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
|
||||
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $NetBSD: nd6_rtr.c,v 1.11 2000/02/06 12:49:48 itojun Exp $ */
|
||||
/* $NetBSD: nd6_rtr.c,v 1.12 2000/02/26 08:39:21 itojun Exp $ */
|
||||
/* $KAME: nd6_rtr.c,v 1.27 2000/02/26 06:53:11 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
@ -97,8 +98,7 @@ nd6_rs_input(m, off, icmp6len)
|
||||
{
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct nd_router_solicit *nd_rs
|
||||
= (struct nd_router_solicit *)((caddr_t)ip6 + off);
|
||||
struct nd_router_solicit *nd_rs;
|
||||
struct in6_addr saddr6 = ip6->ip6_src;
|
||||
#if 0
|
||||
struct in6_addr daddr6 = ip6->ip6_dst;
|
||||
@ -115,13 +115,13 @@ nd6_rs_input(m, off, icmp6len)
|
||||
|
||||
/* If I'm not a router, ignore it. */
|
||||
if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
|
||||
return;
|
||||
goto freeit;
|
||||
|
||||
/* Sanity checks */
|
||||
if (ip6->ip6_hlim != 255) {
|
||||
log(LOG_ERR,
|
||||
"nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -129,13 +129,24 @@ nd6_rs_input(m, off, icmp6len)
|
||||
* This indicates that the src has no IP address assigned yet.
|
||||
*/
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
|
||||
goto freeit;
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
||||
nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
|
||||
if (nd_rs == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
icmp6len -= sizeof(*nd_rs);
|
||||
nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
|
||||
if (nd6_options(&ndopts) < 0) {
|
||||
log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n");
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
if (ndopts.nd_opts_src_lladdr) {
|
||||
@ -151,6 +162,9 @@ nd6_rs_input(m, off, icmp6len)
|
||||
}
|
||||
|
||||
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
|
||||
|
||||
freeit:
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -168,12 +182,11 @@ nd6_ra_input(m, off, icmp6len)
|
||||
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
||||
struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct nd_router_advert *nd_ra =
|
||||
(struct nd_router_advert *)((caddr_t)ip6 + off);
|
||||
struct nd_router_advert *nd_ra;
|
||||
struct in6_addr saddr6 = ip6->ip6_src;
|
||||
#if 0
|
||||
struct in6_addr daddr6 = ip6->ip6_dst;
|
||||
int flags = nd_ra->nd_ra_flags_reserved;
|
||||
int flags; /* = nd_ra->nd_ra_flags_reserved; */
|
||||
int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
|
||||
int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
|
||||
#endif
|
||||
@ -181,26 +194,37 @@ nd6_ra_input(m, off, icmp6len)
|
||||
struct nd_defrouter *dr;
|
||||
|
||||
if (ip6_accept_rtadv == 0)
|
||||
return;
|
||||
goto freeit;
|
||||
|
||||
if (ip6->ip6_hlim != 255) {
|
||||
log(LOG_ERR,
|
||||
"nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
|
||||
log(LOG_ERR,
|
||||
"nd6_ra_input: src %s is not link-local\n",
|
||||
ip6_sprintf(&saddr6));
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
||||
nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
|
||||
if (nd_ra == NULL) {
|
||||
icmp6stat.icp6s_tooshort++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
icmp6len -= sizeof(*nd_ra);
|
||||
nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
|
||||
if (nd6_options(&ndopts) < 0) {
|
||||
log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n");
|
||||
return;
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
{
|
||||
@ -367,6 +391,9 @@ nd6_ra_input(m, off, icmp6len)
|
||||
*/
|
||||
pfxlist_onlink_check();
|
||||
}
|
||||
|
||||
freeit:
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1160,7 +1187,7 @@ in6_ifadd(ifp, in6, addr, prefixlen)
|
||||
in6_len2mask(&mask, prefixlen);
|
||||
|
||||
/* find link-local address (will be interface ID) */
|
||||
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
|
||||
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */
|
||||
if (ifa)
|
||||
ib = (struct in6_ifaddr *)ifa;
|
||||
else
|
||||
@ -1341,7 +1368,7 @@ in6_ifdel(ifp, in6)
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
|
||||
IFAFREE((struct ifaddr *)ia);
|
||||
IFAFREE(&ia->ia_ifa);
|
||||
|
||||
/* lladdr is never deleted */
|
||||
oia = ia;
|
||||
|
Loading…
Reference in New Issue
Block a user