summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/icmp6.h15
-rw-r--r--sys/netinet/tcp_input.c4
-rw-r--r--sys/netinet/tcp_subr.c107
-rw-r--r--sys/netinet/tcp_usrreq.c5
-rw-r--r--sys/netinet/tcp_var.h6
-rw-r--r--sys/netinet/udp_usrreq.c141
-rw-r--r--sys/netinet6/icmp6.c111
-rw-r--r--sys/netinet6/in6_proto.c86
-rw-r--r--sys/netinet6/ip6protosw.h21
9 files changed, 321 insertions, 175 deletions
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 95e38d4801c..749cc8a7567 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: icmp6.h,v 1.11 2000/10/10 15:53:07 itojun Exp $ */
-/* $KAME: icmp6.h,v 1.23 2000/10/10 15:35:45 itojun Exp $ */
+/* $OpenBSD: icmp6.h,v 1.12 2000/12/11 08:04:55 itojun Exp $ */
+/* $KAME: icmp6.h,v 1.24 2000/10/18 19:24:24 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -536,6 +536,7 @@ struct icmp6stat {
#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
+ u_quad_t icp6s_pmtuchg; /* path MTU changes */
};
/*
@@ -556,7 +557,9 @@ struct icmp6stat {
#define ICMPV6CTL_NODEINFO 13
#define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */
#define ICMPV6CTL_ND6_MAXNUDHINT 15
-#define ICMPV6CTL_MAXID 16
+#define ICMPV6CTL_MTUDISC_HIWAT 16
+#define ICMPV6CTL_MTUDISC_LOWAT 17
+#define ICMPV6CTL_MAXID 18
#define ICMPV6CTL_NAMES { \
{ 0, 0 }, \
@@ -575,6 +578,8 @@ struct icmp6stat {
{ "nodeinfo", CTLTYPE_INT }, \
{ "errppslimit", CTLTYPE_INT }, \
{ "nd6_maxnudhint", CTLTYPE_INT }, \
+ { "mtudisc_hiwat", CTLTYPE_INT }, \
+ { "mtudisc_lowat", CTLTYPE_INT }, \
}
#define RTF_PROBEMTU RTF_PROTO1
@@ -596,6 +601,10 @@ void icmp6_redirect_input __P((struct mbuf *, int));
void icmp6_redirect_output __P((struct mbuf *, struct rtentry *));
int icmp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
+struct ip6ctlparam;
+void icmp6_mtudisc_update __P((struct ip6ctlparam *, int));
+void icmp6_mtudisc_callback_register __P((void (*)(struct in6_addr *)));
+
/* XXX: is this the right place for these macros? */
#define icmp6_ifstat_inc(ifp, tag) \
do { \
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index f45766afc53..8fc588e947f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.79 2000/10/14 01:04:10 itojun Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.80 2000/12/11 08:04:55 itojun Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -319,7 +319,7 @@ done:
splx(s);
}
-#if defined(INET6) && !defined(TCP6)
+#ifdef INET6
int
tcp6_input(mp, offp, proto)
struct mbuf **mp;
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 39043f8e7cc..e57ac20961c 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_subr.c,v 1.35 2000/10/13 17:58:36 itojun Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.36 2000/12/11 08:04:55 itojun Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
@@ -152,6 +152,8 @@ tcp_init()
if ((max_linkhdr + sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) >
MHLEN)
panic("tcp_init");
+
+ icmp6_mtudisc_callback_register(tcp6_mtudisc_callback);
#endif /* INET6 */
}
@@ -715,30 +717,39 @@ tcp_notify(inp, error)
sowwakeup(so);
}
-#if defined(INET6) && !defined(TCP6)
+#ifdef INET6
void
tcp6_ctlinput(cmd, sa, d)
int cmd;
struct sockaddr *sa;
void *d;
{
- register struct tcphdr *thp;
+ struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
+ int nmatch;
struct sockaddr_in6 sa6;
- struct mbuf *m;
struct ip6_hdr *ip6;
+ 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))
return;
- if (cmd == PRC_QUENCH)
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+ else if (cmd == PRC_QUENCH) {
+ /* XXX there's no PRC_QUENCH in IPv6 */
notify = tcp_quench;
+ } else if (PRC_IS_REDIRECT(cmd))
+ notify = in_rtchange, d = NULL;
else if (cmd == PRC_MSGSIZE)
- notify = tcp_mtudisc;
- else if (!PRC_IS_REDIRECT(cmd) &&
- ((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
+ ; /* special code is present, see below */
+ else if (cmd == PRC_HOSTDEAD)
+ d = NULL;
+ else if (inet6ctlerrmap[cmd] == 0)
return;
/* if the parameter is from icmp6, decode it. */
@@ -747,6 +758,16 @@ 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);
} else {
m = NULL;
ip6 = NULL;
@@ -756,21 +777,12 @@ tcp6_ctlinput(cmd, sa, d)
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,
+ * XXX: We assume that when ip6 is non NULL,
* M and OFF are valid.
*/
- struct ip6_hdr ip6_tmp;
-
- /* translate addresses into internal form */
- ip6_tmp = *ip6;
- if (IN6_IS_ADDR_LINKLOCAL(&ip6_tmp.ip6_src))
- ip6_tmp.ip6_src.s6_addr16[1] =
- htons(m->m_pkthdr.rcvif->if_index);
- if (IN6_IS_ADDR_LINKLOCAL(&ip6_tmp.ip6_dst))
- ip6_tmp.ip6_dst.s6_addr16[1] =
- htons(m->m_pkthdr.rcvif->if_index);
/* check if we can safely examine src and dst ports */
if (m->m_pkthdr.len < off + sizeof(th))
@@ -785,12 +797,36 @@ tcp6_ctlinput(cmd, sa, d)
thp = &th;
} else
thp = (struct tcphdr *)(mtod(m, caddr_t) + off);
- (void)in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6,
- thp->th_dport, &ip6_tmp.ip6_src,
- thp->th_sport, cmd, notify);
+
+ if (cmd == PRC_MSGSIZE) {
+ int valid = 0;
+
+ /*
+ * Check to see if we have a valid TCP connection
+ * corresponding to the address in the ICMPv6 message
+ * payload.
+ */
+ if (in_pcblookup(&tcbtable, &finaldst,
+ thp->th_dport, &s, thp->th_sport,
+ INPLOOKUP_WILDCARD))
+ 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.
+ */
+ icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
+
+ return;
+ }
+
+ nmatch = in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6,
+ thp->th_dport, &s, thp->th_sport, cmd, notify);
} else {
- (void)in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, 0,
- &zeroin6_addr, 0, cmd, notify);
+ (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, 0,
+ &zeroin6_addr, 0, cmd, notify);
}
}
#endif
@@ -845,7 +881,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);
@@ -925,6 +961,25 @@ 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, EMSGSIZE, tcp_mtudisc);
+}
+#endif /* INET6 */
+
#ifdef TCP_SIGNATURE
int
tcp_signature_tdb_attach()
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index dbcc84d3f25..38a4fc02830 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_usrreq.c,v 1.48 2000/10/14 01:04:11 itojun Exp $ */
+/* $OpenBSD: tcp_usrreq.c,v 1.49 2000/12/11 08:04:56 itojun Exp $ */
/* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
/*
@@ -95,7 +95,7 @@ extern struct baddynamicports baddynamicports;
int tcp_ident __P((void *, size_t *, void *, size_t));
-#if defined(INET6) && !defined(TCP6)
+#ifdef INET6
int
tcp6_usrreq(so, req, m, nam, control, p)
struct socket *so;
@@ -103,6 +103,7 @@ tcp6_usrreq(so, req, m, nam, control, p)
struct mbuf *m, *nam, *control;
struct proc *p;
{
+
return tcp_usrreq(so, req, m, nam, control);
}
#endif
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index c8416d8cc02..fa07feff32b 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_var.h,v 1.33 2000/10/14 01:04:11 itojun Exp $ */
+/* $OpenBSD: tcp_var.h,v 1.34 2000/12/11 08:04:56 itojun Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@@ -349,6 +349,10 @@ int tcp_mss __P((struct tcpcb *, int));
void tcp_mss_update __P((struct tcpcb *));
void tcp_mtudisc __P((struct inpcb *, int));
void tcp_mtudisc_increase __P((struct inpcb *, int));
+#ifdef INET6
+void tcp6_mtudisc __P((struct inpcb *, int));
+void tcp6_mtudisc_callback __P((struct in6_addr *));
+#endif
struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));
void tcp_notify __P((struct inpcb *, int));
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index d3ecb7d686f..6d8bc00de36 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.51 2000/10/13 17:58:37 itojun Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.52 2000/12/11 08:04:56 itojun Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -122,7 +122,7 @@ udp_init()
in_pcbinit(&udbtable, udbhashsize);
}
-#if defined(INET6) && !defined(TCP6)
+#ifdef INET6
int
udp6_input(mp, offp, proto)
struct mbuf **mp;
@@ -650,39 +650,127 @@ udp_notify(inp, errno)
sowwakeup(inp->inp_socket);
}
-#if defined(INET6) && !defined(TCP6)
+#ifdef INET6
void
udp6_ctlinput(cmd, sa, d)
int cmd;
struct sockaddr *sa;
void *d;
{
+ struct udphdr *uhp;
+ struct udphdr uh;
struct sockaddr_in6 sa6;
struct ip6_hdr *ip6;
struct mbuf *m;
int off;
+ struct in6_addr s;
+ struct in6_addr finaldst;
+ void (*notify) __P((struct inpcb *, int)) = udp_notify;
- if (sa == NULL)
+ if (!sa)
return;
- if (sa->sa_family != AF_INET6)
+ if (sa->sa_family != AF_INET6 ||
+ sa->sa_len != sizeof(struct sockaddr_in6))
return;
- /* decode parameter from icmp6. */
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+ if (PRC_IS_REDIRECT(cmd))
+ notify = in_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;
- ip6 = ip6cp->ip6c_ip6;
m = ip6cp->ip6c_m;
+ ip6 = ip6cp->ip6c_ip6;
off = ip6cp->ip6c_off;
- } else
- return;
+
+ /* 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;
+ }
/* 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);
- sa = (struct sockaddr *)&sa6;
- (void)udp_ctlinput(cmd, sa, (void *)ip6);
+ if (ip6) {
+ /*
+ * XXX: We assume that when IPV6 is non NULL,
+ * M and OFF are valid.
+ */
+
+ /* check if we can safely examine src and dst ports */
+ if (m->m_pkthdr.len < off + sizeof(uh))
+ 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);
+
+ 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 0
+ /*
+ * 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.
+ */
+ else if (in_pcblookup(&udbtable, &finaldst,
+ uhp->uh_dport, &s, uhp->uh_sport,
+ INPLOOKUP_WILDCARD | INPLOOKUP_IPV6))
+ 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.
+ */
+ icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
+
+ return;
+ }
+
+ (void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6,
+ uhp->uh_dport, &s, uhp->uh_sport, cmd, notify);
+ } else {
+ (void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6, 0,
+ &zeroin6_addr, 0, cmd, notify);
+ }
}
#endif
@@ -698,6 +786,12 @@ udp_ctlinput(cmd, sa, v)
void (*notify) __P((struct inpcb *, int)) = udp_notify;
int errno;
+ if (!sa)
+ return NULL;
+ if (sa->sa_family != AF_INET ||
+ sa->sa_len != sizeof(struct sockaddr_in))
+ return NULL;
+
if ((unsigned)cmd >= PRC_NCMDS)
return NULL;
errno = inetctlerrmap[cmd];
@@ -707,28 +801,6 @@ udp_ctlinput(cmd, sa, v)
ip = 0;
else if (errno == 0)
return NULL;
- if (sa == NULL)
- return NULL;
-#ifdef INET6
- if (sa->sa_family == AF_INET6) {
- if (ip) {
- struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
-
- /* XXX we assume that the mbuf is sane enough */
-
- uhp = (struct udphdr *)((caddr_t)ip6 + sizeof(*ip6));
-#if 0 /*XXX*/
- in6_pcbnotify(&udbtable, sa, uhp->uh_dport,
- &(ip6->ip6_src), uhp->uh_sport, cmd, udp_notify);
-#endif
- } else {
-#if 0 /*XXX*/
- in6_pcbnotify(&udbtable, sa, 0,
- (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);
-#endif
- }
- } else
-#endif /* INET6 */
if (ip) {
uhp = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
in_pcbnotify(&udbtable, sa, uhp->uh_dport, ip->ip_src,
@@ -1014,7 +1086,7 @@ u_int udp_sendspace = 9216; /* really max datagram size */
u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
/* 40 1K datagrams */
-#if defined(INET6) && !defined(TCP6)
+#ifdef INET6
/*ARGSUSED*/
int
udp6_usrreq(so, req, m, addr, control, p)
@@ -1023,6 +1095,7 @@ udp6_usrreq(so, req, m, addr, control, p)
struct mbuf *m, *addr, *control;
struct proc *p;
{
+
return udp_usrreq(so, req, m, addr, control);
}
#endif
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 52c8fb72b94..086f2b8da03 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: icmp6.c,v 1.25 2000/11/11 00:45:39 itojun Exp $ */
+/* $OpenBSD: icmp6.c,v 1.26 2000/12/11 08:04:56 itojun Exp $ */
/* $KAME: icmp6.c,v 1.156 2000/10/19 19:21:07 itojun Exp $ */
/*
@@ -112,12 +112,26 @@ extern int icmp6errppslim;
static int icmp6errpps_count = 0;
static struct timeval icmp6errppslim_last;
extern int icmp6_nodeinfo;
+
+/*
+ * List of callbacks to notify when Path MTU changes are made.
+ */
+struct icmp6_mtudisc_callback {
+ LIST_ENTRY(icmp6_mtudisc_callback) mc_list;
+ void (*mc_func) __P((struct in6_addr *));
+};
+
+LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks =
+ LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks);
+
static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
extern int pmtu_expire;
+/* XXX do these values make any sense? */
+int icmp6_mtudisc_hiwat = 1280;
+int icmp6_mtudisc_lowat = 256;
+
static void icmp6_errcount __P((struct icmp6errstat *, int, 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 *));
@@ -201,6 +215,29 @@ icmp6_errcount(stat, type, code)
}
/*
+ * Register a Path MTU Discovery callback.
+ */
+void
+icmp6_mtudisc_callback_register(func)
+ void (*func) __P((struct in6_addr *));
+{
+ struct icmp6_mtudisc_callback *mc;
+
+ for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
+ mc = LIST_NEXT(mc, mc_list)) {
+ if (mc->mc_func == func)
+ return;
+ }
+
+ mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
+ if (mc == NULL)
+ panic("icmp6_mtudisc_callback_register");
+
+ mc->mc_func = func;
+ LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
+}
+
+/*
* Generate an error packet of type error in response to bad IP6 packet.
*/
void
@@ -410,7 +447,7 @@ icmp6_input(mp, offp, proto)
#ifdef IPSEC
/* drop it if it does not match the default policy */
if (ipsec6_in_reject(m, NULL)) {
- ipsecstat.in_polvio++;
+ ipsec6stat.in_polvio++;
goto freeit;
}
#endif
@@ -822,7 +859,6 @@ icmp6_input(mp, offp, proto)
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;
@@ -962,19 +998,19 @@ 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);
- }
+ if (finaldst == NULL)
+ finaldst = &((struct ip6_hdr *)(icmp6 + 1))->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;
ctlfunc = (void (*) __P((int, struct sockaddr *, void *)))
(inet6sw[ip6_protox[nxt]].pr_ctlinput);
if (ctlfunc) {
- ip6cp.ip6c_m = m;
- ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
- ip6cp.ip6c_off = eoff;
- (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp);
+ (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6src,
+ &ip6cp);
}
}
break;
@@ -996,16 +1032,38 @@ 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 */
+void
+icmp6_mtudisc_update(ip6cp, validated)
+ struct ip6ctlparam *ip6cp;
+ int validated;
{
+ unsigned long rtcount;
+ struct icmp6_mtudisc_callback *mc;
+ struct in6_addr *dst = ip6cp->ip6c_finaldst;
+ struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
+ struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */
u_int mtu = ntohl(icmp6->icmp6_mtu);
struct rtentry *rt = NULL;
struct sockaddr_in6 sin6;
+ /*
+ * allow non-validated cases if memory is plenty, to make traffic
+ * from non-connected pcb happy.
+ */
+ rtcount = rt_timer_count(icmp6_mtudisc_timeout_q);
+ if (validated) {
+ if (rtcount > icmp6_mtudisc_hiwat)
+ return;
+ else if (rtcount > icmp6_mtudisc_lowat) {
+ /*
+ * XXX nuke a victim, install the new one.
+ */
+ }
+ } else {
+ if (rtcount > icmp6_mtudisc_lowat)
+ return;
+ }
+
bzero(&sin6, sizeof(sin6));
sin6.sin6_family = PF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
@@ -1030,11 +1088,20 @@ icmp6_mtudisc_update(dst, icmp6, m)
rt->rt_rmx.rmx_locks |= RTV_MTU;
} else if (mtu < rt->rt_ifp->if_mtu &&
rt->rt_rmx.rmx_mtu > mtu) {
+ icmp6stat.icp6s_pmtuchg++;
rt->rt_rmx.rmx_mtu = mtu;
}
}
if (rt)
RTFREE(rt);
+
+ /*
+ * Notify protocols that the MTU for this destination
+ * has changed.
+ */
+ for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
+ mc = LIST_NEXT(mc, mc_list))
+ (*mc->mc_func)(&sin6.sin6_addr);
}
/*
@@ -2573,6 +2640,12 @@ icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
case ICMPV6CTL_ND6_MAXNUDHINT:
return sysctl_int(oldp, oldlenp, newp, newlen,
&nd6_maxnudhint);
+ case ICMPV6CTL_MTUDISC_HIWAT:
+ return sysctl_int(oldp, oldlenp, newp, newlen,
+ &icmp6_mtudisc_hiwat);
+ case ICMPV6CTL_MTUDISC_LOWAT:
+ return sysctl_int(oldp, oldlenp, newp, newlen,
+ &icmp6_mtudisc_lowat);
default:
return ENOPROTOOPT;
}
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index e373faa046c..d46491b9cf6 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_proto.c,v 1.25 2000/10/10 15:53:09 itojun Exp $ */
+/* $OpenBSD: in6_proto.c,v 1.26 2000/12/11 08:04:56 itojun Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@@ -130,14 +130,6 @@ struct ip6protosw inet6sw[] = {
0, 0, 0,
udp_sysctl,
},
-#ifdef TCP6
-{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD,
- tcp6_input, 0, tcp6_ctlinput, tcp6_ctloutput,
- tcp6_usrreq,
- tcp6_init, tcp6_fasttimo, tcp6_slowtimo, tcp6_drain,
- tcp6_sysctl,
-},
-#else
{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD,
tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput,
tcp6_usrreq,
@@ -148,7 +140,6 @@ struct ip6protosw inet6sw[] = {
#endif
tcp_sysctl,
},
-#endif /*TCP6*/
{ SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR,
rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput,
rip6_usrreq,
@@ -304,81 +295,6 @@ struct timeval icmp6errratelim = { 0, 0 }; /* no ratelimit */
int icmp6errppslim = 100; /* 100pps */
int icmp6_nodeinfo = 1; /* enable/disable NI response */
-#ifdef TCP6
-/* TCP on IP6 parameters */
-int tcp6_sendspace = 1024 * 8;
-int tcp6_recvspace = 1024 * 8;
-int tcp6_mssdflt = TCP6_MSS;
-int tcp6_rttdflt = TCP6TV_SRTTDFLT / PR_SLOWHZ;
-int tcp6_do_rfc1323 = 1;
-int tcp6_conntimeo = TCP6TV_KEEP_INIT; /* initial connection timeout */
-int tcp6_43maxseg = 0;
-int tcp6_pmtu = 0;
-
-/*
- * Parameters for keepalive option.
- * Connections for which SO_KEEPALIVE is set will be probed
- * after being idle for a time of tcp6_keepidle (in units of PR_SLOWHZ).
- * Starting at that time, the connection is probed at intervals
- * of tcp6_keepintvl (same units) until a response is received
- * or until tcp6_keepcnt probes have been made, at which time
- * the connection is dropped. Note that a tcp6_keepidle value
- * under 2 hours is nonconformant with RFC-1122, Internet Host Requirements.
- */
-int tcp6_keepidle = TCP6TV_KEEP_IDLE; /* time before probing idle */
-int tcp6_keepintvl = TCP6TV_KEEPINTVL; /* interval betwn idle probes */
-int tcp6_keepcnt = TCP6TV_KEEPCNT; /* max idle probes */
-int tcp6_maxpersistidle = TCP6TV_KEEP_IDLE; /* max idle time in persist */
-
-#ifndef INET_SERVER
-#define TCP6_LISTEN_HASH_SIZE 17
-#define TCP6_CONN_HASH_SIZE 97
-#define TCP6_SYN_HASH_SIZE 293
-#define TCP6_SYN_BUCKET_SIZE 35
-#else
-#define TCP6_LISTEN_HASH_SIZE 97
-#define TCP6_CONN_HASH_SIZE 9973
-#define TCP6_SYN_HASH_SIZE 997
-#define TCP6_SYN_BUCKET_SIZE 35
-#endif
-int tcp6_listen_hash_size = TCP6_LISTEN_HASH_SIZE;
-int tcp6_conn_hash_size = TCP6_CONN_HASH_SIZE;
-struct tcp6_hash_list tcp6_listen_hash[TCP6_LISTEN_HASH_SIZE],
- tcp6_conn_hash[TCP6_CONN_HASH_SIZE];
-
-int tcp6_syn_cache_size = TCP6_SYN_HASH_SIZE;
-int tcp6_syn_cache_limit = TCP6_SYN_HASH_SIZE*TCP6_SYN_BUCKET_SIZE;
-int tcp6_syn_bucket_limit = 3*TCP6_SYN_BUCKET_SIZE;
-struct syn_cache_head6 tcp6_syn_cache[TCP6_SYN_HASH_SIZE];
-struct syn_cache_head6 *tcp6_syn_cache_first;
-int tcp6_syn_cache_interval = 8; /* runs timer every 4 seconds */
-int tcp6_syn_cache_timeo = TCP6TV_KEEP_INIT;
-
-/*
- * Parameters for computing a desirable data segment size
- * given an upper bound (either interface MTU, or peer's MSS option)_.
- * As applications tend to use a buffer size that is a multiple
- * of kilobytes, try for something that divides evenly. However,
- * do not round down too much.
- *
- * Round segment size down to a multiple of TCP6_ROUNDSIZE if this
- * does not result in lowering by more than (size/TCP6_ROUNDFRAC).
- * For example, round 536 to 512. Older versions of the system
- * effectively used MCLBYTES (1K or 2K) as TCP6_ROUNDSIZE, with
- * a value of 1 for TCP6_ROUNDFRAC (eliminating its effect).
- * We round to a multiple of 256 for SLIP.
- */
-#ifndef TCP6_ROUNDSIZE
-#define TCP6_ROUNDSIZE 256 /* round to multiple of 256 */
-#endif
-#ifndef TCP6_ROUNDFRAC
-#define TCP6_ROUNDFRAC 10 /* round down at most N/10, or 10% */
-#endif
-
-int tcp6_roundsize = TCP6_ROUNDSIZE;
-int tcp6_roundfrac = TCP6_ROUNDFRAC;
-#endif /*TCP6*/
-
/* UDP on IP6 parameters */
int udp6_sendspace = 9216; /* really max datagram size */
int udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6));
diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h
index 7797403e251..dcbae2d90ae 100644
--- a/sys/netinet6/ip6protosw.h
+++ b/sys/netinet6/ip6protosw.h
@@ -1,9 +1,10 @@
-/* $OpenBSD: ip6protosw.h,v 1.2 1999/12/10 10:04:28 angelos Exp $ */
+/* $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 $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -15,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -81,15 +82,29 @@ struct socket;
struct domain;
struct proc;
struct ip6_hdr;
+struct icmp6_hdr;
+struct in6_addr;
/*
* argument type for the last arg of pr_ctlinput().
* should be consulted only with AF_INET6 family.
+ *
+ * IPv6 ICMP IPv6 [exthdrs] finalhdr paylaod
+ * ^ ^ ^ ^
+ * | | ip6c_ip6 ip6c_off
+ * | ip6c_icmp6
+ * ip6c_m
+ *
+ * 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.
*/
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 in6_addr *ip6c_finaldst; /* final destination address */
};
struct ip6protosw {