summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2004-11-25 15:32:09 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2004-11-25 15:32:09 +0000
commitf7a08eb995954e1589ac898355fdd7c49742f0a8 (patch)
treed44ae27476029ee8d3d991f37c34322339a97014 /sys/netinet
parent7c9e4c2086c4479dbec08dd4d1e199a9864ee907 (diff)
fix for race between invocation for timer and network input
1) add a reaper for TCP and SYN cache states (cf. netbsd pr 20390) 2) additional check for TCP_TIMER_ISARMED(TCPT_REXMT) in tcp_timer_persist() with mickey@; ok deraadt@
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_input.c22
-rw-r--r--sys/netinet/tcp_subr.c21
-rw-r--r--sys/netinet/tcp_timer.c23
-rw-r--r--sys/netinet/tcp_var.h7
4 files changed, 66 insertions, 7 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 57fc27065f6..83acaa05bed 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.177 2004/10/28 19:22:52 mcbride Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.178 2004/11/25 15:32:08 markus Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -3205,6 +3205,7 @@ do { \
#define SYN_CACHE_RM(sc) \
do { \
+ (sc)->sc_flags |= SCF_DEAD; \
TAILQ_REMOVE(&tcp_syn_cache[(sc)->sc_bucketidx].sch_bucket, \
(sc), sc_bucketq); \
(sc)->sc_tp = NULL; \
@@ -3220,7 +3221,8 @@ do { \
(void) m_free((sc)->sc_ipopts); \
if ((sc)->sc_route4.ro_rt != NULL) \
RTFREE((sc)->sc_route4.ro_rt); \
- pool_put(&syn_cache_pool, (sc)); \
+ timeout_set(&(sc)->sc_timer, syn_cache_reaper, (sc)); \
+ timeout_add(&(sc)->sc_timer, 0); \
} while (/*CONSTCOND*/0)
struct pool syn_cache_pool;
@@ -3366,6 +3368,10 @@ syn_cache_timer(void *arg)
int s;
s = splsoftnet();
+ if (sc->sc_flags & SCF_DEAD) {
+ splx(s);
+ return;
+ }
if (__predict_false(sc->sc_rxtshift == TCP_MAXRXTSHIFT)) {
/* Drop it -- too many retransmissions. */
@@ -3398,6 +3404,18 @@ syn_cache_timer(void *arg)
splx(s);
}
+void
+syn_cache_reaper(void *arg)
+{
+ struct syn_cache *sc = arg;
+ int s;
+
+ s = splsoftnet();
+ pool_put(&syn_cache_pool, (sc));
+ splx(s);
+ return;
+}
+
/*
* Remove syn cache created by the specified tcb entry,
* because this does not make sense to keep them
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 0070c1824e0..5a9945f3fb7 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_subr.c,v 1.84 2004/10/28 19:22:52 mcbride Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.85 2004/11/25 15:32:08 markus Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
@@ -495,6 +495,7 @@ tcp_newtcpcb(struct inpcb *inp)
TCP_INIT_DELACK(tp);
for (i = 0; i < TCPT_NTIMERS; i++)
TCP_TIMER_INIT(tp, i);
+ timeout_set(&tp->t_reap_to, tcp_reaper, tp);
#ifdef TCP_SACK
tp->sack_enable = tcp_do_sack;
@@ -593,14 +594,28 @@ tcp_close(struct tcpcb *tp)
#endif
if (tp->t_template)
(void) m_free(tp->t_template);
- pool_put(&tcpcb_pool, tp);
+
+ tp->t_flags |= TF_DEAD;
+ timeout_add(&tp->t_reap_to, 0);
+
inp->inp_ppcb = 0;
soisdisconnected(so);
in_pcbdetach(inp);
- tcpstat.tcps_closed++;
return ((struct tcpcb *)0);
}
+void
+tcp_reaper(void *arg)
+{
+ struct tcpcb *tp = arg;
+ int s;
+
+ s = splsoftnet();
+ pool_put(&tcpcb_pool, tp);
+ splx(s);
+ tcpstat.tcps_closed++;
+}
+
int
tcp_freeq(struct tcpcb *tp)
{
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 60e310cf02c..1a5acbb3e78 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_timer.c,v 1.34 2003/12/10 07:22:43 itojun Exp $ */
+/* $OpenBSD: tcp_timer.c,v 1.35 2004/11/25 15:32:08 markus Exp $ */
/* $NetBSD: tcp_timer.c,v 1.14 1996/02/13 23:44:09 christos Exp $ */
/*
@@ -112,6 +112,10 @@ tcp_delack(void *arg)
*/
s = splsoftnet();
+ if (tp->t_flags & TF_DEAD) {
+ splx(s);
+ return;
+ }
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
splx(s);
@@ -193,6 +197,10 @@ tcp_timer_rexmt(void *arg)
int s;
s = splsoftnet();
+ if (tp->t_flags & TF_DEAD) {
+ splx(s);
+ return;
+ }
#ifdef TCP_SACK
tcp_timer_freesack(tp);
@@ -357,6 +365,11 @@ tcp_timer_persist(void *arg)
int s;
s = splsoftnet();
+ if ((tp->t_flags & TF_DEAD) ||
+ TCP_TIMER_ISARMED(tp, TCPT_REXMT)) {
+ splx(s);
+ return;
+ }
tcpstat.tcps_persisttimeo++;
/*
* Hack: if the peer is dead/unreachable, we do not
@@ -390,6 +403,10 @@ tcp_timer_keep(void *arg)
int s;
s = splsoftnet();
+ if (tp->t_flags & TF_DEAD) {
+ splx(s);
+ return;
+ }
tcpstat.tcps_keeptimeo++;
if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
@@ -444,6 +461,10 @@ tcp_timer_2msl(void *arg)
int s;
s = splsoftnet();
+ if (tp->t_flags & TF_DEAD) {
+ splx(s);
+ return;
+ }
#ifdef TCP_SACK
tcp_timer_freesack(tp);
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 9eb1dc3c0e4..66999823ae4 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_var.h,v 1.67 2004/10/28 19:22:52 mcbride Exp $ */
+/* $OpenBSD: tcp_var.h,v 1.68 2004/11/25 15:32:08 markus Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@@ -84,6 +84,7 @@ struct tcpcb {
#endif
#define TF_REASSLOCK 0x00080000 /* reassembling or draining */
#define TF_LASTIDLE 0x00100000 /* no outstanding ACK on last send */
+#define TF_DEAD 0x00200000 /* dead and to-be-released */
struct mbuf *t_template; /* skeletal packet for transmit */
struct inpcb *t_inpcb; /* back pointer to internet pcb */
@@ -181,6 +182,8 @@ struct tcpcb {
caddr_t t_tuba_pcb; /* next level down pcb for TCP over z */
int pf;
+
+ struct timeout t_reap_to; /* delayed cleanup timeout */
};
#define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb)
@@ -550,6 +553,7 @@ int tcp_attach(struct socket *);
void tcp_canceltimers(struct tcpcb *);
struct tcpcb *
tcp_close(struct tcpcb *);
+void tcp_reaper(void *);
int tcp_freeq(struct tcpcb *);
#if defined(INET6) && !defined(TCP6)
void tcp6_ctlinput(int, struct sockaddr *, void *);
@@ -646,6 +650,7 @@ void syn_cache_reset(struct sockaddr *, struct sockaddr *,
int syn_cache_respond(struct syn_cache *, struct mbuf *);
void syn_cache_timer(void *);
void syn_cache_cleanup(struct tcpcb *);
+void syn_cache_reaper(void *);
#endif /* _KERNEL */
#endif /* _NETINET_TCP_VAR_H_ */