- implement IPv6 pmtud, which is necessary for TCP6.
- fix memory leak on SO_DEBUG over TCP.
This commit is contained in:
parent
a7611f40ee
commit
7fee35f579
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
@ -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++;
|
||||
|
Loading…
Reference in New Issue
Block a user