- implement IPv6 pmtud, which is necessary for TCP6.

- fix memory leak on SO_DEBUG over TCP.
This commit is contained in:
itojun 1999-07-22 12:56:56 +00:00
parent a7611f40ee
commit 7fee35f579
5 changed files with 261 additions and 22 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_input.c,v 1.88 1999/07/17 12:53:05 itojun Exp $ */
/* $NetBSD: tcp_input.c,v 1.89 1999/07/22 12:56:56 itojun Exp $ */
/*
%%% portions-copyright-nrl-95
@ -1132,6 +1132,8 @@ after_listen:
sowwakeup(so);
if (so->so_snd.sb_cc)
(void) tcp_output(tp);
if (tcp_saveti)
m_freem(tcp_saveti);
return;
}
} else if (th->th_ack == tp->snd_una &&
@ -1157,6 +1159,8 @@ after_listen:
TCP_SETUP_ACK(tp, th);
if (tp->t_flags & TF_ACKNOW)
(void) tcp_output(tp);
if (tcp_saveti)
m_freem(tcp_saveti);
return;
}
}
@ -1940,7 +1944,6 @@ dodata: /* XXX */
}
if (so->so_options & SO_DEBUG) {
tcp_trace(TA_INPUT, ostate, tp, tcp_saveti, 0);
m_freem(tcp_saveti);
}
/*
@ -1948,6 +1951,8 @@ dodata: /* XXX */
*/
if (needoutput || (tp->t_flags & TF_ACKNOW))
(void) tcp_output(tp);
if (tcp_saveti)
m_freem(tcp_saveti);
return;
badsyn:
@ -1968,6 +1973,8 @@ dropafterack:
m_freem(m);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
if (tcp_saveti)
m_freem(tcp_saveti);
return;
dropwithreset:
@ -2015,6 +2022,8 @@ dropwithreset:
(void)tcp_respond(tp, m, m, th, th->th_seq + tlen, (tcp_seq)0,
TH_RST|TH_ACK);
}
if (tcp_saveti)
m_freem(tcp_saveti);
return;
drop:
@ -2030,11 +2039,11 @@ drop:
#endif
else
so = NULL;
if (so && (so->so_options & SO_DEBUG) != 0) {
if (so && (so->so_options & SO_DEBUG) != 0)
tcp_trace(TA_DROP, ostate, tp, tcp_saveti, 0);
m_freem(tcp_saveti);
}
}
if (tcp_saveti)
m_freem(tcp_saveti);
m_freem(m);
return;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_subr.c,v 1.72 1999/07/14 22:37:14 itojun Exp $ */
/* $NetBSD: tcp_subr.c,v 1.73 1999/07/22 12:56:56 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -138,6 +138,7 @@
#include <netinet/ip6.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_var.h>
#endif
#include <netinet/tcp.h>
@ -392,6 +393,9 @@ tcp_respond(tp, template, m, th0, ack, seq, flags)
ip6 = NULL;
#endif
if (m == 0) {
if (!template)
return EINVAL;
/* get family information from template */
switch (mtod(template, struct ip *)->ip_v) {
case 4:
@ -411,7 +415,7 @@ tcp_respond(tp, template, m, th0, ack, seq, flags)
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m) {
MCLGET(m, M_DONTWAIT);
if (!(m->m_flags & M_EXT)) {
if ((m->m_flags & M_EXT) == 0) {
m_free(m);
m = NULL;
}
@ -1009,6 +1013,37 @@ tcp_notify(inp, error)
sowwakeup(so);
}
#if defined(INET6) && !defined(TCP6)
void
tcp6_notify(in6p, error)
struct in6pcb *in6p;
int error;
{
register struct tcpcb *tp = (struct tcpcb *)in6p->in6p_ppcb;
register struct socket *so = in6p->in6p_socket;
/*
* Ignore some errors if we are hooked up.
* If connection hasn't completed, has retransmitted several times,
* and receives a second error, give up now. This is better
* than waiting a long time to establish a connection that
* can never complete.
*/
if (tp->t_state == TCPS_ESTABLISHED &&
(error == EHOSTUNREACH || error == ENETUNREACH ||
error == EHOSTDOWN)) {
return;
} else if (TCPS_HAVEESTABLISHED(tp->t_state) == 0 &&
tp->t_rxtshift > 3 && tp->t_softerror)
so->so_error = error;
else
tp->t_softerror = error;
wakeup((caddr_t) &so->so_timeo);
sorwakeup(so);
sowwakeup(so);
}
#endif
#if defined(INET6) && !defined(TCP6)
void
tcp6_ctlinput(cmd, sa, ip6, m, off)
@ -1018,7 +1053,62 @@ tcp6_ctlinput(cmd, sa, ip6, m, off)
struct mbuf *m;
int off;
{
(void)tcp_ctlinput(cmd, sa, (void *)ip6);
register struct tcphdr *thp;
struct tcphdr th;
void (*notify) __P((struct in6pcb *, int)) = tcp6_notify;
int nmatch;
extern struct in6_addr zeroin6_addr; /* netinet6/in6_pcb.c */
if (cmd == PRC_QUENCH)
notify = tcp6_quench;
else if (cmd == PRC_MSGSIZE)
notify = tcp6_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
return;
if (ip6) {
/*
* XXX: We assume that when ip6 is non NULL,
* M and OFF are valid.
*/
/* translate addresses into internal form */
if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
ip6->ip6_src.s6_addr16[1] =
htons(m->m_pkthdr.rcvif->if_index);
}
if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
ip6->ip6_dst.s6_addr16[1] =
htons(m->m_pkthdr.rcvif->if_index);
}
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);
nmatch = in6_pcbnotify(&tcb6, sa, thp->th_dport, &ip6->ip6_src,
thp->th_sport, cmd, 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 = ip6->ip6_src;
syn_cache_unreach((struct sockaddr *)&sin6, sa, thp);
}
} else {
(void) in6_pcbnotify(&tcb6, sa, 0, &zeroin6_addr,
0, cmd, notify);
}
}
#endif
@ -1068,17 +1158,9 @@ tcp_ctlinput(cmd, sa, v)
/* XXX mapped address case */
}
#ifdef INET6
else if (ip && ip->ip_v == 6 && sa->sa_family == AF_INET6) {
/* XXX do something for ip6 */
}
#endif
else {
(void)in_pcbnotifyall(&tcbtable, satosin(sa)->sin_addr, errno,
notify);
#ifdef INET6
/* XXX do something for ip6 */
#endif
}
return NULL;
}
@ -1099,6 +1181,19 @@ tcp_quench(inp, errno)
tp->snd_cwnd = tp->t_segsz;
}
#if defined(INET6) && !defined(TCP6)
void
tcp6_quench(in6p, errno)
struct in6pcb *in6p;
int errno;
{
struct tcpcb *tp = in6totcpcb(in6p);
if (tp)
tp->snd_cwnd = tp->t_segsz;
}
#endif
/*
* On receipt of path MTU corrections, flush old route and replace it
* with the new one. Retransmit all unacknowledged packets, to ensure
@ -1145,6 +1240,48 @@ tcp_mtudisc(inp, errno)
}
}
#if defined(INET6) && !defined(TCP6)
void
tcp6_mtudisc(in6p, errno)
struct in6pcb *in6p;
int errno;
{
struct tcpcb *tp = in6totcpcb(in6p);
struct rtentry *rt = in6_pcbrtentry(in6p);
if (tp != 0) {
if (rt != 0) {
/*
* If this was not a host route, remove and realloc.
*/
if ((rt->rt_flags & RTF_HOST) == 0) {
in6_rtchange(in6p, errno);
if ((rt = in6_pcbrtentry(in6p)) == 0)
return;
}
/*
* Slow start out of the error condition. We
* use the MTU because we know it's smaller
* than the previously transmitted segment.
*
* Note: This is more conservative than the
* suggestion in draft-floyd-incr-init-win-03.
*/
if (rt->rt_rmx.rmx_mtu != 0)
tp->snd_cwnd =
TCP_INITIAL_WINDOW(tcp_init_win,
rt->rt_rmx.rmx_mtu);
}
/*
* Resend unacknowledged packets.
*/
tp->snd_nxt = tp->snd_una;
tcp_output(tp);
}
}
#endif
/*
* Compute the MSS to advertise to the peer. Called only during

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_var.h,v 1.63 1999/07/14 22:37:15 itojun Exp $ */
/* $NetBSD: tcp_var.h,v 1.64 1999/07/22 12:56:56 itojun Exp $ */
/*
%%% portions-copyright-nrl-98
@ -637,14 +637,23 @@ void tcp_input __P((struct mbuf *, ...));
u_long tcp_mss_to_advertise __P((const struct ifnet *));
void tcp_mss_from_peer __P((struct tcpcb *, int));
void tcp_mtudisc __P((struct inpcb *, int));
#if defined(INET6) && !defined(TCP6)
void tcp6_mtudisc __P((struct in6pcb *, int));
#endif
struct tcpcb *
tcp_newtcpcb __P((int, void *));
void tcp_notify __P((struct inpcb *, int));
#if defined(INET6) && !defined(TCP6)
void tcp6_notify __P((struct in6pcb *, int));
#endif
u_int tcp_optlen __P((struct tcpcb *));
int tcp_output __P((struct tcpcb *));
void tcp_pulloutofband __P((struct socket *,
struct tcphdr *, struct mbuf *));
void tcp_quench __P((struct inpcb *, int));
#if defined(INET6) && !defined(TCP6)
void tcp6_quench __P((struct in6pcb *, int));
#endif
int tcp_reass __P((struct tcpcb *, struct tcphdr *, struct mbuf *, int *));
int tcp_respond __P((struct tcpcb *, struct mbuf *, struct mbuf *,
struct tcphdr *, tcp_seq, tcp_seq, int));

View File

@ -1,4 +1,4 @@
/* $NetBSD: icmp6.c,v 1.7 1999/07/22 03:59:42 itojun Exp $ */
/* $NetBSD: icmp6.c,v 1.8 1999/07/22 12:56:57 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -118,6 +118,11 @@ extern struct in6pcb rawin6pcb;
extern struct inpcbhead ripcb;
#endif
extern u_int icmp6errratelim;
#ifdef __NetBSD__
static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
extern int pmtu_expire;
#endif
static int icmp6_rip6_input __P((struct mbuf **, int));
static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
static struct mbuf * ni6_input __P((struct mbuf *, int));
@ -125,6 +130,8 @@ static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
struct ifnet **));
static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
struct ifnet *, int));
static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *));
static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
#ifdef COMPAT_RFC1885
static struct route_in6 icmp6_reflect_rt;
@ -135,6 +142,9 @@ void
icmp6_init()
{
mld6_init();
#ifdef __NetBSD__
icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
#endif
}
/*
@ -394,17 +404,25 @@ icmp6_input(mp, offp, proto)
sin6.sin6_family = PF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_addr = ((struct ip6_hdr *)(icmp6 + 1))->ip6_dst;
rt = rtalloc1((struct sockaddr *)&sin6, 0
#ifdef __NetBSD__
rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/
if (!rt || (rt->rt_flags & RTF_HOST) == 0) {
if (rt)
RTFREE(rt);
rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
}
#endif
#ifdef __FreeBSD__
, RTF_CLONING | RTF_PRCLONING
rt = rtalloc1((struct sockaddr *)&sin6, 0,
RTF_CLONING | RTF_PRCLONING);
#endif /*__FreeBSD__*/
);
#ifdef __bsdi__
bcopy(&sin6, &ro6.ro_dst, sizeof(struct sockaddr_in6));
ro6.ro_rt = 0;
rtcalloc((struct route *)&ro6);
rt = ro6.ro_rt;
#endif /*__bsdi__*/
if (rt && (rt->rt_flags & RTF_HOST)
&& !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
if (mtu < IPV6_MMTU) {
@ -1861,6 +1879,64 @@ icmp6_ratelimit(dst, type, code)
return 0;
}
#ifdef __NetBSD__
static struct rtentry *
icmp6_mtudisc_clone(dst)
struct sockaddr *dst;
{
struct rtentry *rt;
int error;
rt = rtalloc1(dst, 1);
if (rt == 0)
return NULL;
/* If we didn't get a host route, allocate one */
if ((rt->rt_flags & RTF_HOST) == 0) {
struct rtentry *nrt;
error = rtrequest((int) RTM_ADD, dst,
(struct sockaddr *) rt->rt_gateway,
(struct sockaddr *) 0,
RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt);
if (error) {
rtfree(rt);
rtfree(nrt);
return NULL;
}
nrt->rt_rmx = rt->rt_rmx;
rtfree(rt);
rt = nrt;
}
error = rt_timer_add(rt, icmp6_mtudisc_timeout,
icmp6_mtudisc_timeout_q);
if (error) {
rtfree(rt);
return NULL;
}
return rt; /* caller need to call rtfree() */
}
static void
icmp6_mtudisc_timeout(rt, r)
struct rtentry *rt;
struct rttimer *r;
{
if (rt == NULL)
panic("icmp6_mtudisc_timeout: bad route to timeout");
if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
(RTF_DYNAMIC | RTF_HOST)) {
rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
} else {
if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
rt->rt_rmx.rmx_mtu = 0;
}
}
}
#endif /*__NetBSD__*/
#ifdef __bsdi__
void
icmp6_mtuexpire(rt, rtt)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_output.c,v 1.5 1999/07/22 03:59:42 itojun Exp $ */
/* $NetBSD: ip6_output.c,v 1.6 1999/07/22 12:56:57 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -521,10 +521,18 @@ skip_ipsec2:;
* ifp must point it.
*/
if (ro->ro_rt == 0) {
#ifdef __NetBSD__
/*
* NetBSD always clones routes, if parent is
* PRF_CLONING.
*/
rtalloc((struct route *)ro);
#else
if (ro == &ip6route) /* xxx kazu */
rtalloc((struct route *)ro);
else
rtcalloc((struct route *)ro);
#endif
}
if (ro->ro_rt == 0) {
ip6stat.ip6s_noroute++;