pull latest kame pcbnotify code. synchronizes ICMPv6 path mtu discovery

behavior with other protocols (i.e. validation, use of hiwat/lowat).
This commit is contained in:
itojun 2001-02-11 06:49:49 +00:00
parent 9e66537acb
commit bc5a6e2482
12 changed files with 411 additions and 271 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_subr.c,v 1.106 2001/01/24 09:04:16 itojun Exp $ */
/* $NetBSD: tcp_subr.c,v 1.107 2001/02/11 06:49:49 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -1110,16 +1110,14 @@ tcp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct in6pcb *, int)) = tcp6_notify;
int nmatch;
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
const struct sockaddr_in6 *sa6_src = NULL;
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
struct mbuf *m;
int off;
struct in6_addr finaldst;
struct in6_addr s;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@ -1144,26 +1142,13 @@ tcp6_ctlinput(cmd, sa, d)
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
/* translate addresses into internal form */
bcopy(ip6cp->ip6c_finaldst, &finaldst, sizeof(finaldst));
if (IN6_IS_ADDR_LINKLOCAL(&finaldst)) {
finaldst.s6_addr16[1] =
htons(m->m_pkthdr.rcvif->if_index);
}
bcopy(&ip6->ip6_src, &s, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s))
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
sa6_src = ip6cp->ip6c_src;
} else {
m = NULL;
ip6 = NULL;
sa6_src = &sa6_any;
}
/* translate addresses into internal form */
sa6 = *(struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (ip6) {
/*
* XXX: We assume that when ip6 is non NULL,
@ -1174,15 +1159,8 @@ tcp6_ctlinput(cmd, sa, d)
if (m->m_pkthdr.len < off + sizeof(th))
return;
if (m->m_len < off + sizeof(th)) {
/*
* this should be rare case,
* so we compromise on this copy...
*/
m_copydata(m, off, sizeof(th), (caddr_t)&th);
thp = &th;
} else
thp = (struct tcphdr *)(mtod(m, caddr_t) + off);
bzero(&th, sizeof(th));
m_copydata(m, off, sizeof(th), (caddr_t)&th);
if (cmd == PRC_MSGSIZE) {
int valid = 0;
@ -1192,38 +1170,38 @@ tcp6_ctlinput(cmd, sa, d)
* corresponding to the address in the ICMPv6 message
* payload.
*/
if (in6_pcblookup_connect(&tcb6, &finaldst,
thp->th_dport, &s, thp->th_sport, 0))
if (in6_pcblookup_connect(&tcb6, &sa6->sin6_addr,
th.th_dport, (struct in6_addr *)&sa6_src->sin6_addr,
th.th_sport, 0))
valid++;
/*
* Now that we've validated that we are actually
* communicating with the host indicated in the ICMPv6
* message, recalculate the new MTU, and create the
* corresponding routing entry.
* Depending on the value of "valid" and routing table
* size (mtudisc_{hi,lo}wat), we will:
* - recalcurate the new MTU and create the
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
/*
* no need to call in6_pcbnotify, it should have been
* called via callback if necessary
*/
return;
}
nmatch = in6_pcbnotify(&tcb6, (struct sockaddr *)&sa6,
thp->th_dport, &s, thp->th_sport, cmd, notify);
nmatch = in6_pcbnotify(&tcb6, sa, th.th_dport,
(struct sockaddr *)sa6_src, th.th_sport, cmd, NULL, notify);
if (nmatch == 0 && syn_cache_count &&
(inet6ctlerrmap[cmd] == EHOSTUNREACH ||
inet6ctlerrmap[cmd] == ENETUNREACH ||
inet6ctlerrmap[cmd] == EHOSTDOWN)) {
struct sockaddr_in6 sin6;
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
sin6.sin6_port = thp->th_sport;
sin6.sin6_addr = s;
syn_cache_unreach((struct sockaddr *)&sin6, sa, thp);
}
inet6ctlerrmap[cmd] == EHOSTDOWN))
syn_cache_unreach((struct sockaddr *)sa6_src,
sa, &th);
} else {
(void) in6_pcbnotify(&tcb6, (struct sockaddr *)&sa6, 0,
&zeroin6_addr, 0, cmd, notify);
(void) in6_pcbnotify(&tcb6, sa, 0, (struct sockaddr *)sa6_src,
0, cmd, NULL, notify);
}
}
#endif
@ -1409,7 +1387,7 @@ tcp6_mtudisc_callback(faddr)
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_addr = *faddr;
(void) in6_pcbnotify(&tcb6, (struct sockaddr *)&sin6, 0,
&zeroin6_addr, 0, PRC_MSGSIZE, tcp6_mtudisc);
(struct sockaddr *)&sa6_any, 0, PRC_MSGSIZE, NULL, tcp6_mtudisc);
}
void

View File

@ -1,5 +1,5 @@
/* $NetBSD: ah_input.c,v 1.24 2001/01/24 09:04:16 itojun Exp $ */
/* $KAME: ah_input.c,v 1.48 2001/01/23 08:59:37 itojun Exp $ */
/* $NetBSD: ah_input.c,v 1.25 2001/02/11 06:49:51 itojun Exp $ */
/* $KAME: ah_input.c,v 1.51 2001/02/08 14:24:05 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -1046,9 +1046,9 @@ ah6_ctlinput(cmd, sa, d)
struct secasvar *sav;
struct ip6_hdr *ip6;
struct mbuf *m;
struct ip6ctlparam *ip6cp = NULL;
int off;
struct in6_addr finaldst;
struct in6_addr s;
struct sockaddr_in6 sa6_src, sa6_dst;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@ -1058,20 +1058,10 @@ ah6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
/* translate addresses into internal form */
bcopy(ip6cp->ip6c_finaldst, &finaldst, sizeof(finaldst));
if (IN6_IS_ADDR_LINKLOCAL(&finaldst)) {
finaldst.s6_addr16[1] =
htons(m->m_pkthdr.rcvif->if_index);
}
bcopy(&ip6->ip6_src, &s, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s))
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
} else {
m = NULL;
ip6 = NULL;
@ -1104,8 +1094,10 @@ ah6_ctlinput(cmd, sa, d)
* Check to see if we have a valid SA corresponding to
* the address in the ICMP message payload.
*/
sav = key_allocsa(AF_INET6, (caddr_t)&s,
(caddr_t)&finaldst, IPPROTO_AH, ahp->ah_spi);
sav = key_allocsa(AF_INET6,
(caddr_t)&sa6_src.sin6_addr,
(caddr_t)&sa6_dst.sin6_addr,
IPPROTO_AH, ahp->ah_spi);
if (sav) {
if (sav->state == SADB_SASTATE_MATURE ||
sav->state == SADB_SASTATE_DYING)
@ -1116,14 +1108,13 @@ ah6_ctlinput(cmd, sa, d)
/* XXX Further validation? */
/*
* Now that we've validated that we are actually
* communicating with the host indicated in the ICMPv6
* message, recalculate the new MTU, and create the
* corresponding routing entry.
* Depending on the value of "valid" and routing table
* size (mtudisc_{hi,lo}wat), we will:
* - recalcurate the new MTU and create the
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
return;
}
/* we normally notify single pcb here */

View File

@ -1,5 +1,5 @@
/* $NetBSD: esp_input.c,v 1.14 2001/01/24 09:04:16 itojun Exp $ */
/* $KAME: esp_input.c,v 1.50 2001/01/23 08:59:37 itojun Exp $ */
/* $NetBSD: esp_input.c,v 1.15 2001/02/11 06:49:51 itojun Exp $ */
/* $KAME: esp_input.c,v 1.52 2001/02/07 04:58:47 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -946,12 +946,12 @@ esp6_ctlinput(cmd, sa, d)
{
const struct newesp *espp;
struct newesp esp;
struct ip6ctlparam *ip6cp = NULL, ip6cp1;
struct secasvar *sav;
struct ip6_hdr *ip6;
struct mbuf *m;
int off;
struct in6_addr finaldst;
struct in6_addr s;
struct sockaddr_in6 sa6_src, sa6_dst;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@ -961,20 +961,10 @@ esp6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
/* translate addresses into internal form */
bcopy(ip6cp->ip6c_finaldst, &finaldst, sizeof(finaldst));
if (IN6_IS_ADDR_LINKLOCAL(&finaldst)) {
finaldst.s6_addr16[1] =
htons(m->m_pkthdr.rcvif->if_index);
}
bcopy(&ip6->ip6_src, &s, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s))
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
} else {
m = NULL;
ip6 = NULL;
@ -982,6 +972,24 @@ esp6_ctlinput(cmd, sa, d)
if (ip6) {
/*
* Notify the error to all possible sockets via pfctlinput2.
* Since the upper layer information (such as protocol type,
* source and destination ports) is embedded in the encrypted
* data and might have been cut, we can't directly call
* an upper layer ctlinput function. However, the pcbnotify
* function will consider source and destination addresses
* as well as the flow info value, and may be able to find
* some PCB that should be notified.
* Although pfctlinput2 will call esp6_ctlinput(), there is
* no possibility of an infinite loop of function calls,
* because we don't pass the inner IPv6 header.
*/
bzero(&ip6cp1, sizeof(ip6cp1));
ip6cp1.ip6c_src = ip6cp->ip6c_src;
pfctlinput2(cmd, sa, (void *)&ip6cp1);
/*
* Then go to special cases that need ESP header information.
* XXX: We assume that when ip6 is non NULL,
* M and OFF are valid.
*/
@ -1002,12 +1010,15 @@ esp6_ctlinput(cmd, sa, d)
if (cmd == PRC_MSGSIZE) {
int valid = 0;
/*
* Check to see if we have a valid SA corresponding to
* the address in the ICMP message payload.
*/
sav = key_allocsa(AF_INET6, (caddr_t)&s,
(caddr_t)&finaldst, IPPROTO_ESP, espp->esp_spi);
sav = key_allocsa(AF_INET6,
(caddr_t)&sa6_src.sin6_addr,
(caddr_t)&sa6_dst, IPPROTO_ESP,
espp->esp_spi);
if (sav) {
if (sav->state == SADB_SASTATE_MATURE ||
sav->state == SADB_SASTATE_DYING)
@ -1018,17 +1029,14 @@ esp6_ctlinput(cmd, sa, d)
/* XXX Further validation? */
/*
* Now that we've validated that we are actually
* communicating with the host indicated in the ICMPv6
* message, recalculate the new MTU, and create the
* corresponding routing entry.
* Depending on the value of "valid" and routing table
* size (mtudisc_{hi,lo}wat), we will:
* - recalcurate the new MTU and create the
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
return;
}
/* we normally notify single pcb here */
} else {
/* we normally notify any pcb here */
}

View File

@ -1,5 +1,5 @@
/* $NetBSD: icmp6.c,v 1.57 2001/02/11 04:53:49 itojun Exp $ */
/* $KAME: icmp6.c,v 1.194 2001/02/08 15:19:12 itojun Exp $ */
/* $NetBSD: icmp6.c,v 1.58 2001/02/11 06:49:51 itojun Exp $ */
/* $KAME: icmp6.c,v 1.198 2001/02/11 04:51:12 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -155,6 +155,7 @@ static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
struct ifnet **, char *));
static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
struct ifnet *, int));
static int icmp6_notify_error __P((struct mbuf *, int, int, int));
static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *));
static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
static void icmp6_redirect_timeout __P((struct rtentry *, struct rttimer *));
@ -404,7 +405,6 @@ icmp6_input(mp, offp, proto)
int off = *offp;
int icmp6len = m->m_pkthdr.len - *offp;
int code, sum, noff;
struct sockaddr_in6 icmp6src;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
@ -841,37 +841,69 @@ icmp6_input(mp, offp, proto)
break;
}
deliver:
if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
icmp6stat.icp6s_tooshort++;
goto freeit;
if (icmp6_notify_error(m, off, icmp6len, code)) {
/* In this case, m should've been freed. */
return(IPPROTO_DONE);
}
#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
bzero(&icmp6src, sizeof(icmp6src));
icmp6src.sin6_len = sizeof(struct sockaddr_in6);
icmp6src.sin6_family = AF_INET6;
icmp6src.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
break;
/* Detect the upper level protocol */
{
badcode:
icmp6stat.icp6s_badcode++;
break;
badlen:
icmp6stat.icp6s_badlen++;
break;
}
/* deliver the packet to appropriate sockets */
icmp6_rip6_input(&m, *offp);
return IPPROTO_DONE;
freeit:
m_freem(m);
return IPPROTO_DONE;
}
static int
icmp6_notify_error(m, off, icmp6len, code)
struct mbuf *m;
int off, icmp6len;
{
struct icmp6_hdr *icmp6;
struct ip6_hdr *eip6;
u_int32_t notifymtu;
struct sockaddr_in6 icmp6src, icmp6dst;
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),
-1);
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(-1);
}
#endif
eip6 = (struct ip6_hdr *)(icmp6 + 1);
/* Detect the upper level protocol */
{
void (*ctlfunc) __P((int, struct sockaddr *, void *));
struct ip6_hdr *eip6 = (struct ip6_hdr *)(icmp6 + 1);
u_int8_t nxt = eip6->ip6_nxt;
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;
@ -887,15 +919,15 @@ icmp6_input(mp, offp, proto)
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff +
sizeof(struct ip6_ext),
IPPROTO_DONE);
-1);
eh = (struct ip6_ext *)(mtod(m, caddr_t)
+ eoff);
#else
IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
eoff, sizeof(*eh));
eoff, sizeof(*eh));
if (eh == NULL) {
icmp6stat.icp6s_tooshort++;
return IPPROTO_DONE;
return(-1);
}
#endif
@ -916,15 +948,15 @@ icmp6_input(mp, offp, proto)
*/
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth),
IPPROTO_DONE);
-1);
rth = (struct ip6_rthdr *)(mtod(m, caddr_t)
+ eoff);
#else
IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
eoff, sizeof(*rth));
eoff, sizeof(*rth));
if (rth == NULL) {
icmp6stat.icp6s_tooshort++;
return IPPROTO_DONE;
return(-1);
}
#endif
rthlen = (rth->ip6r_len + 1) << 3;
@ -942,7 +974,7 @@ icmp6_input(mp, offp, proto)
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff + rthlen,
IPPROTO_DONE);
-1);
rth0 = (struct ip6_rthdr0 *)(mtod(m, caddr_t) + eoff);
#else
IP6_EXTHDR_GET(rth0,
@ -950,7 +982,7 @@ icmp6_input(mp, offp, proto)
eoff, rthlen);
if (rth0 == NULL) {
icmp6stat.icp6s_tooshort++;
return IPPROTO_DONE;
return(-1);
}
#endif
/* just ignore a bogus header */
@ -965,15 +997,15 @@ icmp6_input(mp, offp, proto)
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, eoff +
sizeof(struct ip6_frag),
IPPROTO_DONE);
-1);
fh = (struct ip6_frag *)(mtod(m, caddr_t)
+ eoff);
#else
IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
eoff, sizeof(*fh));
eoff, sizeof(*fh));
if (fh == NULL) {
icmp6stat.icp6s_tooshort++;
return IPPROTO_DONE;
return(-1);
}
#endif
/*
@ -1000,49 +1032,87 @@ icmp6_input(mp, offp, proto)
goto notify;
}
}
notify:
notify:
#ifndef PULLDOWN_TEST
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));
sizeof(*icmp6) + sizeof(struct ip6_hdr));
if (icmp6 == NULL) {
icmp6stat.icp6s_tooshort++;
return IPPROTO_DONE;
return(-1);
}
#endif
eip6 = (struct ip6_hdr *)(icmp6 + 1);
bzero(&icmp6dst, sizeof(icmp6dst));
icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
icmp6dst.sin6_family = AF_INET6;
if (finaldst == NULL)
finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
icmp6dst.sin6_addr = eip6->ip6_dst;
else
icmp6dst.sin6_addr = *finaldst;
icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
&icmp6dst.sin6_addr);
#ifndef SCOPEDROUTING
if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
NULL, NULL)) {
/* should be impossbile */
nd6log((LOG_DEBUG,
"icmp6_notify_error: in6_embedscope failed\n"));
goto freeit;
}
#endif
/*
* retrieve parameters from the inner IPv6 header, and convert
* them into sockaddr structures.
*/
bzero(&icmp6src, sizeof(icmp6src));
icmp6src.sin6_len = sizeof(struct sockaddr_in6);
icmp6src.sin6_family = AF_INET6;
icmp6src.sin6_addr = eip6->ip6_src;
icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
&icmp6src.sin6_addr);
#ifndef SCOPEDROUTING
if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
NULL, NULL)) {
/* should be impossbile */
nd6log((LOG_DEBUG,
"icmp6_notify_error: in6_embedscope failed\n"));
goto freeit;
}
#endif
icmp6src.sin6_flowinfo =
(eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
if (finaldst == NULL)
finaldst = &eip6->ip6_dst;
ip6cp.ip6c_m = m;
ip6cp.ip6c_icmp6 = icmp6;
ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
ip6cp.ip6c_off = eoff;
ip6cp.ip6c_finaldst = finaldst;
ip6cp.ip6c_src = &icmp6src;
ip6cp.ip6c_nxt = nxt;
if (icmp6type == ICMP6_PACKET_TOO_BIG) {
notifymtu = ntohl(icmp6->icmp6_mtu);
ip6cp.ip6c_cmdarg = (void *)&notifymtu;
}
ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
(inet6sw[ip6_protox[nxt]].pr_ctlinput);
if (ctlfunc) {
(void) (*ctlfunc)(code, (struct sockaddr *)&icmp6src,
&ip6cp);
(void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,
&ip6cp);
}
}
break;
badcode:
icmp6stat.icp6s_badcode++;
break;
badlen:
icmp6stat.icp6s_badlen++;
break;
}
return(0);
icmp6_rip6_input(&m, *offp);
return IPPROTO_DONE;
freeit:
freeit:
m_freem(m);
return IPPROTO_DONE;
return(-1);
}
void

View File

@ -1,5 +1,5 @@
/* $NetBSD: in6.c,v 1.42 2001/02/11 04:29:30 itojun Exp $ */
/* $KAME: in6.c,v 1.107 2000/10/06 04:58:30 itojun Exp $ */
/* $NetBSD: in6.c,v 1.43 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: in6.c,v 1.175 2001/02/10 15:44:58 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -119,6 +119,9 @@ const struct in6_addr in6mask64 = IN6MASK64;
const struct in6_addr in6mask96 = IN6MASK96;
const struct in6_addr in6mask128 = IN6MASK128;
const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
0, 0, IN6ADDR_ANY_INIT, 0};
static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
struct ifnet *, struct proc *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6.h,v 1.21 2000/10/17 21:46:42 itojun Exp $ */
/* $NetBSD: in6.h,v 1.22 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: in6.h,v 1.57 2000/08/26 10:00:45 itojun Exp $ */
/*
@ -163,6 +163,8 @@ struct sockaddr_in6 {
#endif
#ifdef _KERNEL
extern const struct sockaddr_in6 sa6_any;
extern const struct in6_addr in6mask0;
extern const struct in6_addr in6mask32;
extern const struct in6_addr in6mask64;

View File

@ -1,5 +1,5 @@
/* $NetBSD: in6_pcb.c,v 1.34 2001/02/10 04:14:27 itojun Exp $ */
/* $KAME: in6_pcb.c,v 1.64 2000/10/01 12:37:20 itojun Exp $ */
/* $NetBSD: in6_pcb.c,v 1.35 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -379,12 +379,8 @@ in6_pcbconnect(in6p, nam)
|| (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
&& in6p->in6p_laddr.s6_addr32[3] == 0)) {
if (in6p->in6p_lport == 0) {
#ifdef __NetBSD__
(void)in6_pcbbind(in6p, (struct mbuf *)0,
(struct proc *)0);
#else
(void)in6_pcbbind(in6p, (struct mbuf *)0);
#endif
}
in6p->in6p_laddr = *in6a;
}
@ -482,29 +478,39 @@ in6_setpeeraddr(in6p, nam)
* any errors for each matching socket.
*
* Must be called at splsoftnet.
*
* Note: src (4th arg) carries the flowlabel value on the original IPv6
* header, in sin6_flowinfo member.
*/
int
in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
struct in6pcb *head;
struct sockaddr *dst;
struct sockaddr *dst, *src;
u_int fport_arg, lport_arg;
struct in6_addr *laddr6;
int cmd;
void *cmdarg;
void (*notify) __P((struct in6pcb *, int));
{
struct in6pcb *in6p, *nin6p;
struct in6_addr faddr6;
struct sockaddr_in6 sa6_src, *sa6_dst;
u_int16_t fport = fport_arg, lport = lport_arg;
int errno;
int nmatch = 0;
int do_rtchange = (notify == in6_rtchange);
u_int32_t flowinfo;
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
return 0;
faddr6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
sa6_dst = (struct sockaddr_in6 *)dst;
if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
return 0;
/*
* note that src can be NULL when we get notify by local fragmentation.
*/
sa6_src = (src == NULL) ? sa6_any : *(struct sockaddr_in6 *)src;
flowinfo = sa6_src.sin6_flowinfo;
/*
* Redirects go to all references to the destination,
* and use in6_rtchange to invalidate the route cache.
@ -516,48 +522,85 @@ in6_pcbnotify(head, dst, fport_arg, laddr6, lport_arg, cmd, notify)
if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
fport = 0;
lport = 0;
bzero((caddr_t)laddr6, sizeof(*laddr6));
bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr));
do_rtchange = 1;
if (cmd != PRC_HOSTDEAD)
notify = in6_rtchange;
}
if (notify == NULL)
return 0;
errno = inet6ctlerrmap[cmd];
for (in6p = head->in6p_next; in6p != head; in6p = nin6p) {
nin6p = in6p->in6p_next;
if (do_rtchange) {
/*
* Since a non-connected PCB might have a cached route,
* we always call in6_rtchange without matching
* the PCB to the src/dst pair.
*
* XXX: we assume in6_rtchange does not free the PCB.
*/
if (IN6_ARE_ADDR_EQUAL(&in6p->in6p_route.ro_dst.sin6_addr,
&faddr6)) {
in6_rtchange(in6p, errno);
/*
* Under the following condition, notify of redirects
* to the pcb, without making address matches against inpcb.
* - redirect notification is arrived.
* - the inpcb is unconnected.
* - the inpcb is caching !RTF_HOST routing entry.
* - the ICMPv6 notification is from the gateway cached in the
* inpcb. i.e. ICMPv6 notification is from nexthop gateway
* the inpcb used very recently.
*
* This is to improve interaction between netbsd/openbsd
* redirect handling code, and inpcb route cache code.
* without the clause, !RTF_HOST routing entry (which carries
* gateway used by inpcb right before the ICMPv6 redirect)
* will be cached forever in unconnected inpcb.
*
* There still is a question regarding to what is TRT:
* - On bsdi/freebsd, RTF_HOST (cloned) routing entry will be
* generated on packet output. inpcb will always cache
* RTF_HOST routing entry so there's no need for the clause
* (ICMPv6 redirect will update RTF_HOST routing entry,
* and inpcb is caching it already).
* However, bsdi/freebsd are vulnerable to local DoS attacks
* due to the cloned routing entries.
* - Specwise, "destination cache" is mentioned in RFC2461.
* Jinmei says that it implies bsdi/freebsd behavior, itojun
* is not really convinced.
* - Having hiwat/lowat on # of cloned host route (redirect/
* pmtud) may be a good idea. netbsd/openbsd has it. see
* icmp6_mtudisc_update().
*/
if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
in6p->in6p_route.ro_rt &&
!(in6p->in6p_route.ro_rt->rt_flags & RTF_HOST)) {
struct sockaddr_in6 *dst6;
if (notify == in6_rtchange) {
/* there's nothing to do any more */
continue;
}
}
dst6 = (struct sockaddr_in6 *)&in6p->in6p_route.ro_dst;
if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
&sa6_dst->sin6_addr))
goto do_notify;
}
/* at this point, we can assume that NOTIFY is not NULL. */
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &faddr6) ||
/*
* Detect if we should notify the error. If no source and
* destination ports are specifed, but non-zero flowinfo and
* local address match, notify the error. This is the case
* when the error is delivered with an encrypted buffer
* by ESP. Otherwise, just compare addresses and ports
* as usual.
*/
if (lport == 0 && fport == 0 && flowinfo &&
in6p->in6p_socket != NULL &&
flowinfo == (in6p->in6p_flowinfo & IPV6_FLOWLABEL_MASK) &&
IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &sa6_src.sin6_addr))
goto do_notify;
else if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
&sa6_dst->sin6_addr) ||
in6p->in6p_socket == 0 ||
(lport && in6p->in6p_lport != lport) ||
(!IN6_IS_ADDR_UNSPECIFIED(laddr6) &&
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) ||
(!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
&sa6_src.sin6_addr)) ||
(fport && in6p->in6p_fport != fport))
continue;
(*notify)(in6p, errno);
do_notify:
if (notify)
(*notify)(in6p, errno);
nmatch++;
}
return nmatch;

View File

@ -1,5 +1,5 @@
/* $NetBSD: in6_pcb.h,v 1.14 2001/02/08 14:56:15 itojun Exp $ */
/* $KAME: in6_pcb.h,v 1.44 2001/02/06 09:16:53 itojun Exp $ */
/* $NetBSD: in6_pcb.h,v 1.15 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -162,7 +162,7 @@ struct in6pcb *
struct in6_addr *, u_int, struct in6_addr *,
u_int, int));
int in6_pcbnotify __P((struct in6pcb *, struct sockaddr *,
u_int, struct in6_addr *, u_int, int,
u_int, struct sockaddr *, u_int, int, void *,
void (*)(struct in6pcb *, int)));
void in6_pcbpurgeif __P((struct in6pcb *, struct ifnet *));
void in6_rtchange __P((struct in6pcb *, int));

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_proto.c,v 1.24 2001/02/11 05:25:04 itojun Exp $ */
/* $NetBSD: in6_proto.c,v 1.25 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@ -162,7 +162,7 @@ struct ip6protosw inet6sw[] = {
0, 0, 0, 0,
},
{ SOCK_RAW, &inet6domain, IPPROTO_ICMPV6, PR_ATOMIC | PR_ADDR,
icmp6_input, rip6_output, 0, rip6_ctloutput,
icmp6_input, rip6_output, rip6_ctlinput, rip6_ctloutput,
rip6_usrreq,
icmp6_init, icmp6_fasttimo, 0, 0,
icmp6_sysctl,

View File

@ -1,5 +1,5 @@
/* $NetBSD: ip6protosw.h,v 1.9 2001/02/10 04:14:29 itojun Exp $ */
/* $KAME: ip6protosw.h,v 1.14 2000/10/18 18:15:53 itojun Exp $ */
/* $NetBSD: ip6protosw.h,v 1.10 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: ip6protosw.h,v 1.22 2001/02/08 18:02:08 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -98,13 +98,21 @@ struct in6_addr;
* ip6c_finaldst usually points to ip6c_ip6->ip6_dst. if the original
* (internal) packet carries a routing header, it may point the final
* dstination address in the routing header.
*
* ip6c_src: ip6c_ip6->ip6_src + scope info + flowlabel in ip6c_ip6
* (beware of flowlabel, if you try to compare it against others)
* ip6c_dst: ip6c_finaldst + scope info
*/
struct ip6ctlparam {
struct mbuf *ip6c_m; /* start of mbuf chain */
struct icmp6_hdr *ip6c_icmp6; /* icmp6 header of target packet */
struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */
int ip6c_off; /* offset of the target proto header */
struct sockaddr_in6 *ip6c_src; /* srcaddr w/ additional info */
struct sockaddr_in6 *ip6c_dst; /* (final) dstaddr w/ additional info */
struct in6_addr *ip6c_finaldst; /* final destination address */
void *ip6c_cmdarg; /* control command dependent data */
u_int8_t ip6c_nxt; /* final next header field */
};
struct ip6protosw {

View File

@ -1,4 +1,4 @@
/* $NetBSD: raw_ip6.c,v 1.28 2001/02/10 04:14:29 itojun Exp $ */
/* $NetBSD: raw_ip6.c,v 1.29 2001/02/11 06:49:52 itojun Exp $ */
/* $KAME: raw_ip6.c,v 1.65 2001/02/08 18:36:17 itojun Exp $ */
/*
@ -234,11 +234,14 @@ rip6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
int off;
struct ip6ctlparam *ip6cp = NULL;
const struct sockaddr_in6 *sa6_src = NULL;
void *cmdarg;
void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
int nxt;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@ -250,43 +253,82 @@ rip6_ctlinput(cmd, sa, d)
notify = in6_rtchange, d = NULL;
else if (cmd == PRC_HOSTDEAD)
d = NULL;
else if (cmd == PRC_MSGSIZE)
; /* special code is present, see below */
else if (inet6ctlerrmap[cmd] == 0)
return;
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
cmdarg = ip6cp->ip6c_cmdarg;
sa6_src = ip6cp->ip6c_src;
nxt = ip6cp->ip6c_nxt;
} else {
m = NULL;
ip6 = NULL;
cmdarg = NULL;
sa6_src = &sa6_any;
nxt = -1;
}
/* translate addresses into internal form */
sa6 = *(struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (ip6 && cmd == PRC_MSGSIZE) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
int valid = 0;
struct in6pcb *in6p;
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
* Check to see if we have a valid raw IPv6 socket
* corresponding to the address in the ICMPv6 message
* payload, and the protocol (ip6_nxt) meets the socket.
* XXX chase extension headers, or pass final nxt value
* from icmp6_notify_error()
*/
struct in6_addr s;
in6p = NULL;
in6p = in6_pcblookup_connect(&rawin6pcb,
&sa6->sin6_addr, 0,
(struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
#if 0
if (!in6p) {
/*
* As the use of sendto(2) is fairly popular,
* we may want to allow non-connected pcb too.
* But it could be too weak against attacks...
* We should at least check if the local
* address (= s) is really ours.
*/
in6p = in6_pcblookup_bind(&rawin6pcb,
&sa6->sin6_addr, 0, 0))
}
#endif
/* translate addresses into internal form */
bcopy(&ip6->ip6_src, &s, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s))
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (in6p && in6p->in6p_ip6.ip6_nxt &&
in6p->in6p_ip6.ip6_nxt == nxt)
valid++;
(void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6,
0, &s, 0, cmd, notify);
} else {
(void) in6_pcbnotify(&rawin6pcb, (struct sockaddr *)&sa6, 0,
&zeroin6_addr, 0, cmd, notify);
/*
* Depending on the value of "valid" and routing table
* size (mtudisc_{hi,lo}wat), we will:
* - recalcurate the new MTU and create the
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
/*
* regardless of if we called icmp6_mtudisc_update(),
* we need to call in6_pcbnotify(), to notify path
* MTU change to the userland (2292bis-02), because
* some unconnected sockets may share the same
* destination and want to know the path MTU.
*/
}
(void) in6_pcbnotify(&rawin6pcb, sa, 0,
(struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
}
/*

View File

@ -1,5 +1,5 @@
/* $NetBSD: udp6_usrreq.c,v 1.39 2001/02/10 04:14:29 itojun Exp $ */
/* $KAME: udp6_usrreq.c,v 1.62 2000/10/19 01:11:05 itojun Exp $ */
/* $NetBSD: udp6_usrreq.c,v 1.40 2001/02/11 06:49:53 itojun Exp $ */
/* $KAME: udp6_usrreq.c,v 1.84 2001/02/07 07:38:25 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -467,15 +467,19 @@ udp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
struct udphdr *uhp;
struct udphdr uh;
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
struct mbuf *m;
int off;
struct in6_addr s;
struct in6_addr finaldst;
void *cmdarg;
struct ip6ctlparam *ip6cp = NULL;
const struct sockaddr_in6 *sa6_src = NULL;
void (*notify) __P((struct in6pcb *, int)) = udp6_notify;
struct udp_portonly {
u_int16_t uh_sport;
u_int16_t uh_dport;
} *uhp;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@ -494,30 +498,19 @@ udp6_ctlinput(cmd, sa, d)
/* if the parameter is from icmp6, decode it. */
if (d != NULL) {
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
ip6cp = (struct ip6ctlparam *)d;
m = ip6cp->ip6c_m;
ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
/* translate addresses into internal form */
bcopy(ip6cp->ip6c_finaldst, &finaldst, sizeof(finaldst));
if (IN6_IS_ADDR_LINKLOCAL(&finaldst)) {
finaldst.s6_addr16[1] =
htons(m->m_pkthdr.rcvif->if_index);
}
bcopy(&ip6->ip6_src, &s, sizeof(s));
if (IN6_IS_ADDR_LINKLOCAL(&s))
s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
cmdarg = ip6cp->ip6c_cmdarg;
sa6_src = ip6cp->ip6c_src;
} else {
m = NULL;
ip6 = NULL;
cmdarg = NULL;
sa6_src = &sa6_any;
}
/* translate addresses into internal form */
sa6 = *(struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
@ -525,28 +518,23 @@ udp6_ctlinput(cmd, sa, d)
*/
/* check if we can safely examine src and dst ports */
if (m->m_pkthdr.len < off + sizeof(uh))
if (m->m_pkthdr.len < off + sizeof(*uhp))
return;
if (m->m_len < off + sizeof(uh)) {
/*
* this should be rare case,
* so we compromise on this copy...
*/
m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
uhp = &uh;
} else
uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
bzero(&uh, sizeof(uh));
m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
if (cmd == PRC_MSGSIZE) {
int valid = 0;
/*
* Check to see if we have a valid UDP socket
* corresponding to the address in the ICMPv6 message
* payload.
*/
if (in6_pcblookup_connect(&udb6, &finaldst,
uhp->uh_dport, &s, uhp->uh_sport, 0))
if (in6_pcblookup_connect(&udb6, &sa6->sin6_addr,
uh.uh_dport, (struct in6_addr *)&sa6_src->sin6_addr,
uh.uh_sport, 0))
valid++;
#if 0
/*
@ -556,28 +544,35 @@ udp6_ctlinput(cmd, sa, d)
* We should at least check if the local address (= s)
* is really ours.
*/
else if (in6_pcblookup_bind(&udb6, &finaldst,
uhp->uh_dport, 0))
else if (in6_pcblookup_bind(&udb6, &sa6->sin6_addr,
uh.uh_dport, 0))
valid++;
#endif
/*
* Now that we've validated that we are actually
* communicating with the host indicated in the ICMPv6
* message, recalculate the new MTU, and create the
* corresponding routing entry.
* Depending on the value of "valid" and routing table
* size (mtudisc_{hi,lo}wat), we will:
* - recalcurate the new MTU and create the
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
return;
/*
* regardless of if we called icmp6_mtudisc_update(),
* we need to call in6_pcbnotify(), to notify path
* MTU change to the userland (2292bis-02), because
* some unconnected sockets may share the same
* destination and want to know the path MTU.
*/
}
(void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6,
uhp->uh_dport, &s,
uhp->uh_sport, cmd, notify);
(void) in6_pcbnotify(&udb6, sa, uh.uh_dport,
(struct sockaddr *)sa6_src, uh.uh_sport, cmd, cmdarg,
notify);
} else {
(void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 0,
&zeroin6_addr, 0, cmd, notify);
(void) in6_pcbnotify(&udb6, sa, 0, (struct sockaddr *)sa6_src,
0, cmd, cmdarg, notify);
}
}