summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2001-02-16 16:01:01 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2001-02-16 16:01:01 +0000
commitecd82efc92808a3b9161e0fb0fb90d746ce8a310 (patch)
tree265dd7dea85ff82beafdb73a72622554ddc95020
parentadcce09577c48aeb228910c0f7e4f83726f03ff2 (diff)
pull in new pcb notification code from kame. better handling of scope address.
-rw-r--r--sys/netinet/in_pcb.h4
-rw-r--r--sys/netinet/tcp_subr.c114
-rw-r--r--sys/netinet/udp_usrreq.c148
-rw-r--r--sys/netinet6/icmp6.c194
-rw-r--r--sys/netinet6/in6.h6
-rw-r--r--sys/netinet6/in6_pcb.c121
-rw-r--r--sys/netinet6/in6_prefix.h4
-rw-r--r--sys/netinet6/ip6_input.c4
-rw-r--r--sys/netinet6/ip6protosw.h12
-rw-r--r--sys/netinet6/mld6.c35
-rw-r--r--sys/netinet6/raw_ip6.c102
11 files changed, 490 insertions, 254 deletions
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index b6f8853704c..de65f08b901 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.h,v 1.31 2001/02/16 14:45:11 itojun Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.32 2001/02/16 16:00:53 itojun Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
@@ -263,7 +263,7 @@ struct rtentry *
/* INET6 stuff */
int in6_pcbnotify __P((struct inpcbtable *, struct sockaddr *,
- u_int, struct in6_addr *, u_int, int,
+ u_int, struct sockaddr *, u_int, int, void *,
void (*)(struct inpcb *, int)));
struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *,
struct ip6_pktopts *,
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 3309968706e..c3c8c678c01 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_subr.c,v 1.38 2000/12/21 00:54:10 itojun Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.39 2001/02/16 16:00:54 itojun Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
@@ -724,16 +724,17 @@ tcp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
- struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct inpcb *, int)) = tcp_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;
+ struct {
+ u_int16_t th_sport;
+ u_int16_t th_dport;
+ } *thp;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@@ -758,26 +759,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,
@@ -785,18 +773,15 @@ tcp6_ctlinput(cmd, sa, d)
*/
/* check if we can safely examine src and dst ports */
- if (m->m_pkthdr.len < off + sizeof(th))
+ if (m->m_pkthdr.len < off + sizeof(*thp))
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));
+#ifdef DIAGNOSTIC
+ if (sizeof(*thp) > sizeof(th))
+ panic("assumption failed in tcp6_ctlinput");
+#endif
+ m_copydata(m, off, sizeof(*thp), (caddr_t)&th);
if (cmd == PRC_MSGSIZE) {
int valid = 0;
@@ -806,27 +791,32 @@ tcp6_ctlinput(cmd, sa, d)
* corresponding to the address in the ICMPv6 message
* payload.
*/
- if (in_pcblookup(&tcbtable, &finaldst,
- thp->th_dport, &s, thp->th_sport,
- INPLOOKUP_WILDCARD))
+ if (in6_pcbhashlookup(&tcbtable, &sa6->sin6_addr,
+ th.th_dport, (struct in6_addr *)&sa6_src->sin6_addr,
+ th.th_sport))
+ valid++;
+ else if (in_pcblookup(&tcbtable, &sa6->sin6_addr,
+ th.th_dport, (struct in6_addr *)&sa6_src->sin6_addr,
+ th.th_sport, INPLOOKUP_IPV6))
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);
return;
}
- nmatch = in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6,
- thp->th_dport, &s, thp->th_sport, cmd, notify);
+ (void) in6_pcbnotify(&tcbtable, sa, th.th_dport,
+ (struct sockaddr *)sa6_src, th.th_sport, cmd, NULL, notify);
} else {
- (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, 0,
- &zeroin6_addr, 0, cmd, notify);
+ (void) in6_pcbnotify(&tcbtable, sa, 0,
+ (struct sockaddr *)sa6_src, 0, cmd, NULL, notify);
}
}
#endif
@@ -881,7 +871,7 @@ tcp_ctlinput(cmd, sa, v)
if (ip) {
th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
in_pcbnotify(&tcbtable, sa, th->th_dport, ip->ip_src,
- th->th_sport, errno, notify);
+ th->th_sport, errno, notify);
} else
in_pcbnotifyall(&tcbtable, sa, errno, notify);
@@ -903,6 +893,25 @@ tcp_quench(inp, errno)
tp->snd_cwnd = tp->t_maxseg;
}
+#ifdef INET6
+/*
+ * Path MTU Discovery handlers.
+ */
+void
+tcp6_mtudisc_callback(faddr)
+ struct in6_addr *faddr;
+{
+ struct sockaddr_in6 sin6;
+
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *faddr;
+ (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sin6, 0,
+ (struct sockaddr *)&sa6_any, 0, PRC_MSGSIZE, NULL, tcp_mtudisc);
+}
+#endif /* INET6 */
+
/*
* On receipt of path MTU corrections, flush old route and replace it
* with the new one. Retransmit all unacknowledged packets, to ensure
@@ -961,25 +970,6 @@ tcp_mtudisc_increase(inp, errno)
}
}
-#ifdef INET6
-/*
- * Path MTU Discovery handlers.
- */
-void
-tcp6_mtudisc_callback(faddr)
- struct in6_addr *faddr;
-{
- struct sockaddr_in6 sin6;
-
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_addr = *faddr;
- (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sin6, 0,
- &zeroin6_addr, 0, PRC_MSGSIZE, tcp_mtudisc);
-}
-#endif /* INET6 */
-
#ifdef TCP_SIGNATURE
int
tcp_signature_tdb_attach()
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 6d8bc00de36..ba13ec596d8 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.52 2000/12/11 08:04:56 itojun Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.53 2001/02/16 16:00:54 itojun Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -657,17 +657,21 @@ udp6_ctlinput(cmd, sa, d)
struct sockaddr *sa;
void *d;
{
- struct udphdr *uhp;
struct udphdr uh;
struct sockaddr_in6 sa6;
- struct ip6_hdr *ip6;
+ register struct ip6_hdr *ip6;
struct mbuf *m;
int off;
- struct in6_addr s;
+ void *cmdarg;
+ struct ip6ctlparam *ip6cp = NULL;
struct in6_addr finaldst;
+ struct udp_portonly {
+ u_int16_t uh_sport;
+ u_int16_t uh_dport;
+ } *uhp;
void (*notify) __P((struct inpcb *, int)) = udp_notify;
- if (!sa)
+ if (sa == NULL)
return;
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
@@ -686,60 +690,96 @@ 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;
} else {
m = NULL;
ip6 = NULL;
+ cmdarg = NULL;
+ /* XXX: translate addresses into internal form */
+ sa6 = *(struct sockaddr_in6 *)sa;
+#ifndef SCOPEDROUTING
+ if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL, NULL)) {
+ /* should be impossbile */
+ printf("udp6_ctlinput: in6_embedscope failed\n");
+ return;
+ }
+#endif
}
- /* 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 (ip6cp && ip6cp->ip6c_finaldst) {
+ bzero(&sa6, sizeof(sa6));
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_len = sizeof(sa6);
+ sa6.sin6_addr = *ip6cp->ip6c_finaldst;
+ /* XXX: assuming M is valid in this case */
+ sa6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ ip6cp->ip6c_finaldst);
+#ifndef SCOPEDROUTING
+ if (in6_embedscope(ip6cp->ip6c_finaldst, &sa6, NULL, NULL)) {
+ /* should be impossbile */
+ printf("udp6_ctlinput: in6_embedscope failed\n");
+ return;
+ }
+#endif
+ } else {
+ /* XXX: translate addresses into internal form */
+ sa6 = *(struct sockaddr_in6 *)sa;
+#ifndef SCOPEDROUTING
+ if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL, NULL)) {
+ /* should be impossbile */
+ printf("udp6_ctlinput: in6_embedscope failed\n");
+ return;
+ }
+#endif
+ }
if (ip6) {
/*
* XXX: We assume that when IPV6 is non NULL,
* M and OFF are valid.
*/
+ struct sockaddr_in6 sa6_src;
/* 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);
+
+ bzero(&sa6_src, sizeof(sa6_src));
+ sa6_src.sin6_family = AF_INET6;
+ sa6_src.sin6_len = sizeof(sa6_src);
+ sa6_src.sin6_addr = ip6->ip6_src;
+ sa6_src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &ip6->ip6_src);
+#ifndef SCOPEDROUTING
+ if (in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL, NULL)) {
+ /* should be impossbile */
+ printf("udp6_ctlinput: in6_embedscope failed\n");
+ return;
+ }
+#endif
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 (in_pcblookup(&udbtable, &finaldst, uhp->uh_dport,
- &s, uhp->uh_sport, INPLOOKUP_IPV6))
- valid++;
+ if (in6_pcbhashlookup(&udbtable, &finaldst,
+ uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport))
+ valid = 1;
+ else if (in_pcblookup(&udbtable, &sa6.sin6_addr,
+ uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport,
+ INPLOOKUP_IPV6))
+ valid = 1;
#if 0
/*
* As the use of sendto(2) is fairly popular,
@@ -748,28 +788,36 @@ udp6_ctlinput(cmd, sa, d)
* We should at least check if the local address (= s)
* is really ours.
*/
- else if (in_pcblookup(&udbtable, &finaldst,
- uhp->uh_dport, &s, uhp->uh_sport,
+ else if (in_pcblookup(&udbtable, &sa6.sin6_addr,
+ uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport,
INPLOOKUP_WILDCARD | INPLOOKUP_IPV6))
- valid++;
+ valid = 1;
#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(&udbtable, (struct sockaddr *)&sa6,
- uhp->uh_dport, &s, uhp->uh_sport, cmd, notify);
+ uh.uh_dport, (struct sockaddr *)&sa6_src,
+ uh.uh_sport, cmd, cmdarg, notify);
} else {
(void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6, 0,
- &zeroin6_addr, 0, cmd, notify);
+ (struct sockaddr *)&sa6_any, 0, cmd, cmdarg, notify);
}
}
#endif
@@ -786,7 +834,7 @@ udp_ctlinput(cmd, sa, v)
void (*notify) __P((struct inpcb *, int)) = udp_notify;
int errno;
- if (!sa)
+ if (sa == NULL)
return NULL;
if (sa->sa_family != AF_INET ||
sa->sa_len != sizeof(struct sockaddr_in))
@@ -945,11 +993,12 @@ udp_output(m, va_alist)
int payload = sizeof(struct ip6_hdr);
struct in6_addr *laddr;
struct ifnet *oifp = NULL;
+ int flags;
struct sockaddr_in6 tmp;
ipv6->ip6_flow = htonl(0x60000000) |
(inp->inp_ipv6.ip6_flow & htonl(0x0fffffff));
-
+
ipv6->ip6_nxt = IPPROTO_UDP;
if (sin6)
tmp = *sin6;
@@ -988,6 +1037,12 @@ udp_output(m, va_alist)
uh->uh_ulen = htons(ipv6->ip6_plen);
uh->uh_sum = 0;
+ flags = 0;
+#ifdef IN6P_MINMTU
+ if (inp->inp_flags & IN6P_MINMTU)
+ flags |= IPV6_MINMTU;
+#endif
+
/*
* Always calculate udp checksum for IPv6 datagrams
*/
@@ -996,8 +1051,7 @@ udp_output(m, va_alist)
uh->uh_sum = 0xffff;
error = ip6_output(m, inp->inp_outputopts6, &inp->inp_route6,
- inp->inp_socket->so_options & SO_DONTROUTE,
- inp->inp_moptions6, NULL);
+ flags, inp->inp_moptions6, NULL);
} else
#endif /* INET6 */
{
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index f94b6df8dba..25b4d787cb5 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: icmp6.c,v 1.32 2001/02/08 18:46:22 itojun Exp $ */
-/* $KAME: icmp6.c,v 1.195 2001/02/08 15:35:31 itojun Exp $ */
+/* $OpenBSD: icmp6.c,v 1.33 2001/02/16 16:00:55 itojun Exp $ */
+/* $KAME: icmp6.c,v 1.201 2001/02/16 12:23:40 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -179,6 +179,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 *));
@@ -200,7 +201,7 @@ icmp6_errcount(stat, type, code)
struct icmp6errstat *stat;
int type, code;
{
- switch(type) {
+ switch (type) {
case ICMP6_DST_UNREACH:
switch (code) {
case ICMP6_DST_UNREACH_NOROUTE:
@@ -224,7 +225,7 @@ icmp6_errcount(stat, type, code)
stat->icp6errs_packet_too_big++;
return;
case ICMP6_TIME_EXCEEDED:
- switch(code) {
+ switch (code) {
case ICMP6_TIME_EXCEED_TRANSIT:
stat->icp6errs_time_exceed_transit++;
return;
@@ -234,7 +235,7 @@ icmp6_errcount(stat, type, code)
}
break;
case ICMP6_PARAM_PROB:
- switch(code) {
+ switch (code) {
case ICMP6_PARAMPROB_HEADER:
stat->icp6errs_paramprob_header++;
return;
@@ -423,7 +424,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);
@@ -860,37 +860,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);
}
+ break;
+
+ 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),
- IPPROTO_DONE);
- icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
+ 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 IPPROTO_DONE;
- }
+ IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
+ sizeof(*icmp6) + sizeof(struct ip6_hdr));
+ if (icmp6 == NULL) {
+ icmp6stat.icp6s_tooshort++;
+ return(-1);
+ }
#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;
+ eip6 = (struct ip6_hdr *)(icmp6 + 1);
- /* Detect the upper level protocol */
- {
+ /* 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;
@@ -899,22 +931,22 @@ icmp6_input(mp, offp, proto)
while (1) { /* XXX: should avoid inf. loop explicitly? */
struct ip6_ext *eh;
- switch(nxt) {
+ switch (nxt) {
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_AH:
#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
@@ -935,15 +967,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;
@@ -961,7 +993,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,
@@ -969,7 +1001,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 */
@@ -984,15 +1016,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
/*
@@ -1024,44 +1056,82 @@ icmp6_input(mp, offp, proto)
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
@@ -1615,7 +1685,7 @@ ni6_addrs(ni6, m, ifpp, subj)
int niflags = ni6->ni_flags;
if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
- switch(ni6->ni_code) {
+ switch (ni6->ni_code) {
case ICMP6_NI_SUBJ_IPV6:
if (subj == NULL) /* must be impossible... */
return(0);
@@ -1656,7 +1726,7 @@ ni6_addrs(ni6, m, ifpp, subj)
*/
/* What do we have to do about ::1? */
- switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
+ switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
case IPV6_ADDR_SCOPE_LINKLOCAL:
if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
continue;
@@ -1742,7 +1812,7 @@ ni6_store_addrs(ni6, nni6, ifp0, resid)
continue; /* we now collect deprecated addrs */
/* What do we have to do about ::1? */
- switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
+ switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
case IPV6_ADDR_SCOPE_LINKLOCAL:
if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
continue;
@@ -2686,7 +2756,7 @@ icmp6_ctloutput(op, so, level, optname, mp)
return EINVAL;
}
- switch(op) {
+ switch (op) {
case PRCO_SETOPT:
switch (optname) {
case ICMP6_FILTER:
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 26b5095186a..71e65293c56 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: in6.h,v 1.18 2000/10/17 21:46:19 itojun Exp $ */
-/* $KAME: in6.h,v 1.52 2000/07/15 15:28:02 itojun Exp $ */
+/* $OpenBSD: in6.h,v 1.19 2001/02/16 16:00:56 itojun Exp $ */
+/* $KAME: in6.h,v 1.77 2001/02/09 06:17:40 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -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;
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index a596849812f..d99f1d87e6e 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_pcb.c,v 1.24 2001/02/16 08:22:05 itojun Exp $ */
+/* $OpenBSD: in6_pcb.c,v 1.25 2001/02/16 16:00:56 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -554,28 +554,36 @@ in6_pcbconnect(inp, nam)
* Must be called at splnet.
*/
int
-in6_pcbnotify(head, dst, fport_arg, la, lport_arg, cmd, notify)
+in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify)
struct inpcbtable *head;
- struct sockaddr *dst;
+ struct sockaddr *dst, *src;
uint fport_arg;
- struct in6_addr *la;
uint lport_arg;
int cmd;
+ void *cmdarg;
void (*notify) __P((struct inpcb *, int));
{
struct inpcb *inp, *ninp;
- struct in6_addr *faddr,laddr = *la;
u_short fport = fport_arg, lport = lport_arg;
+ struct sockaddr_in6 sa6_src, *sa6_dst;
int errno, nmatch = 0;
- int do_rtchange = (notify == in_rtchange);
+ u_int32_t flowinfo;
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET6)
return 1;
- faddr = &(((struct sockaddr_in6 *)dst)->sin6_addr);
- if (IN6_IS_ADDR_UNSPECIFIED(faddr))
+
+ sa6_dst = (struct sockaddr_in6 *)dst;
+ if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
return 1;
- if (IN6_IS_ADDR_V4MAPPED(faddr))
- printf("Huh? Thought in6_pcbnotify() never got called with mapped!\n");
+ if (IN6_IS_ADDR_V4MAPPED(&sa6_dst->sin6_addr))
+ printf("Huh? Thought in6_pcbnotify() never got "
+ "called with mapped!\n");
+
+ /*
+ * 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,
@@ -588,9 +596,10 @@ in6_pcbnotify(head, dst, fport_arg, la, lport_arg, cmd, notify)
if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
fport = 0;
lport = 0;
- laddr = in6addr_any;
+ sa6_src.sin6_addr = in6addr_any;
- notify = in_rtchange;
+ if (cmd != PRC_HOSTDEAD)
+ notify = in_rtchange;
}
errno = inet6ctlerrmap[cmd];
@@ -598,39 +607,77 @@ in6_pcbnotify(head, dst, fport_arg, la, lport_arg, cmd, notify)
inp != (struct inpcb *)&head->inpt_queue; inp = ninp) {
ninp = inp->inp_queue.cqe_next;
-#ifdef INET6
if ((inp->inp_flags & INP_IPV6) == 0)
continue;
-#endif
-
- if (do_rtchange) {
- /*
- * Since a non-connected PCB might have a cached route,
- * we always call in_rtchange without matching
- * the PCB to the src/dst pair.
- *
- * XXX: we assume in_rtchange does not free the PCB.
- */
- if (IN6_ARE_ADDR_EQUAL(&inp->inp_route6.ro_dst.sin6_addr,
- faddr)) {
- in_rtchange(inp, errno);
- if (notify == in_rtchange) {
- /* there's nothing to do any more */
- continue;
- }
- }
+ /*
+ * 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(&inp->inp_laddr6) &&
+ inp->inp_route.ro_rt &&
+ !(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
+ struct sockaddr_in6 *dst6;
+
+ dst6 = (struct sockaddr_in6 *)&inp->inp_route.ro_dst;
+ if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
+ &sa6_dst->sin6_addr))
+ goto do_notify;
}
- if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) ||
- !inp->inp_socket ||
- (lport && inp->inp_lport != lport) ||
- (!IN6_IS_ADDR_UNSPECIFIED(&laddr) && !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &laddr)) ||
- (fport && inp->inp_fport != fport)) {
+ /*
+ * 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 &&
+ inp->inp_socket != NULL &&
+ flowinfo == (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK) &&
+ IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, &sa6_src.sin6_addr))
+ goto do_notify;
+ else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
+ &sa6_dst->sin6_addr) ||
+ inp->inp_socket == 0 ||
+ (lport && inp->inp_lport != lport) ||
+ (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) &&
+ !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
+ &sa6_src.sin6_addr)) ||
+ (fport && inp->inp_fport != fport)) {
continue;
}
+ do_notify:
nmatch++;
-
if (notify)
(*notify)(inp, errno);
}
diff --git a/sys/netinet6/in6_prefix.h b/sys/netinet6/in6_prefix.h
index c8ba52446ff..0647e255eb7 100644
--- a/sys/netinet6/in6_prefix.h
+++ b/sys/netinet6/in6_prefix.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: in6_prefix.h,v 1.3 2001/02/08 14:51:22 itojun Exp $ */
-/* $KAME: in6_prefix.h,v 1.9 2001/02/08 10:57:00 itojun Exp $ */
+/* $OpenBSD: in6_prefix.h,v 1.4 2001/02/16 16:00:57 itojun Exp $ */
+/* $KAME: in6_prefix.h,v 1.10 2001/02/08 16:30:30 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, 1998 and 1999 WIDE Project.
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 02f37e21cf0..87425ebfec3 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_input.c,v 1.25 2001/02/16 14:58:12 itojun Exp $ */
+/* $OpenBSD: ip6_input.c,v 1.26 2001/02/16 16:00:57 itojun Exp $ */
/* $KAME: ip6_input.c,v 1.176 2001/02/14 07:13:39 itojun Exp $ */
/*
@@ -970,7 +970,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
/* RFC 2292 sec. 5 */
if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) {
- struct in6_pktinfo pi6, *prevpi = NULL;
+ struct in6_pktinfo pi6;
bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr));
if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr))
pi6.ipi6_addr.s6_addr16[1] = 0;
diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h
index dcbae2d90ae..1dbe69fb175 100644
--- a/sys/netinet6/ip6protosw.h
+++ b/sys/netinet6/ip6protosw.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ip6protosw.h,v 1.3 2000/12/11 08:04:56 itojun Exp $ */
-/* $KAME: ip6protosw.h,v 1.14 2000/10/18 18:15:53 itojun Exp $ */
+/* $OpenBSD: ip6protosw.h,v 1.4 2001/02/16 16:00:58 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 {
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 5a8dba7b6ac..badc566b512 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: mld6.c,v 1.8 2001/02/16 08:48:06 itojun Exp $ */
-/* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */
+/* $OpenBSD: mld6.c,v 1.9 2001/02/16 16:00:58 itojun Exp $ */
+/* $KAME: mld6.c,v 1.26 2001/02/16 14:50:35 itojun Exp $ */
/*
* Copyright (C) 1998 WIDE Project.
@@ -189,31 +189,34 @@ mld6_input(m, off)
struct in6_ifaddr *ia;
int timer; /* timer value in the MLD query header */
+#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
+
/* source address validation */
+ ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */
if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
log(LOG_ERR,
- "mld6_input: src %s is not link-local\n",
- ip6_sprintf(&ip6->ip6_src));
+ "mld6_input: src %s is not link-local (grp=%s)\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&mldh->mld6_addr));
/*
* 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.
+ * XXX: do we have to allow :: as source?
*/
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.
*
@@ -231,7 +234,7 @@ mld6_input(m, off)
break;
if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) &&
- !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr))
+ !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr))
break; /* print error or log stat? */
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
mldh->mld6_addr.s6_addr16[1] =
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 783be6eb8b8..486b931ffa1 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: raw_ip6.c,v 1.1 2001/02/08 18:46:23 itojun Exp $ */
+/* $OpenBSD: raw_ip6.c,v 1.2 2001/02/16 16:01:00 itojun Exp $ */
/* $KAME: raw_ip6.c,v 1.65 2001/02/08 18:36:17 itojun Exp $ */
/*
@@ -261,11 +261,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))
@@ -277,43 +280,102 @@ rip6_ctlinput(cmd, sa, d)
notify = in6_rtchange, d = NULL;
else if (cmd == PRC_HOSTDEAD)
d = NULL;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ else if (cmd == PRC_MSGSIZE)
+ ; /* special code is present, see below */
+#endif
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 defined(__NetBSD__) || defined(__OpenBSD__)
+ 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;
+#ifdef __NetBSD__
+ in6p = in6_pcblookup_connect(&rawin6pcb,
+ &sa6->sin6_addr, 0,
+ (struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
+#elif defined(__OpenBSD__)
+ in6p = in6_pcbhashlookup(&rawin6pcbtable, &sa6->sin6_addr, 0,
+ (struct in6_addr *)&sa6_src->sin6_addr, 0);
+#endif
+#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.
+ */
+#ifdef __NetBSD__
+ in6p = in6_pcblookup_bind(&rawin6pcb,
+ &sa6->sin6_addr, 0, 0))
+#elif defined(__OpenBSD__)
+ in6p = in_pcblookup(&rawin6pcbtable, &sa6->sin6_addr, 0,
+ (struct in6_addr *)&sa6_src->sin6_addr, 0,
+ INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+#endif
+ }
+#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(&rawin6pcbtable, (struct sockaddr *)&sa6,
- 0, &s, 0, cmd, notify);
- } else {
- (void) in6_pcbnotify(&rawin6pcbtable, (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.
+ */
}
+#endif
+
+#ifdef __OpenBSD__
+ (void) in6_pcbnotify(&rawin6pcbtable, sa, 0,
+ (struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
+#else
+ (void) in6_pcbnotify(&rawin6pcb, sa, 0,
+ (struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
+#endif
}
/*