From 3cbe7fafa5a0aefbb7fb95770d75b1ef35b6f545 Mon Sep 17 00:00:00 2001 From: Robert Watson Date: Sun, 9 Apr 2006 16:59:19 +0000 Subject: [PATCH] Modify tcp_timewait() to accept an inpcb reference, not a tcptw reference. For now, we allow the possibility that the in_ppcb pointer in the inpcb may be NULL if a timewait socket has had its tcptw structure recycled. This allows tcp_timewait() to consistently unlock the inpcb. Reported by: Kazuaki Oda MFC after: 3 months --- sys/netinet/tcp_input.c | 23 ++++++++++++----------- sys/netinet/tcp_reass.c | 23 ++++++++++++----------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 0532f71b5d9e..c31892ccd76d 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -173,7 +173,7 @@ static int tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *); static void tcp_xmit_timer(struct tcpcb *, int); static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); -static int tcp_timewait(struct tcptw *, struct tcpopt *, +static int tcp_timewait(struct inpcb *, struct tcpopt *, struct tcphdr *, struct mbuf *, int); /* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */ @@ -760,7 +760,7 @@ findpcb: */ if (thflags & TH_SYN) tcp_dooptions(&to, optp, optlen, 1); - if (tcp_timewait(intotw(inp), &to, th, m, tlen)) + if (tcp_timewait(inp, &to, th, m, tlen)) goto findpcb; /* * tcp_timewait unlocks inp. @@ -3141,13 +3141,14 @@ tcp_newreno_partial_ack(tp, th) * looking for a pcb in the listen state. Returns 0 otherwise. */ static int -tcp_timewait(tw, to, th, m, tlen) - struct tcptw *tw; +tcp_timewait(inp, to, th, m, tlen) + struct inpcb *inp; struct tcpopt *to; struct tcphdr *th; struct mbuf *m; int tlen; { + struct tcptw *tw; int thflags; tcp_seq seq; #ifdef INET6 @@ -3156,19 +3157,20 @@ tcp_timewait(tw, to, th, m, tlen) const int isipv6 = 0; #endif + /* tcbinfo lock required for tcp_twclose(), tcp_2msl_reset. */ + INP_INFO_WLOCK_ASSERT(&tcbinfo); + INP_LOCK_ASSERT(inp); + /* * XXXRW: Time wait state for inpcb has been recycled, but inpcb is * still present. This is undesirable, but temporarily necessary * until we work out how to handle inpcb's who's timewait state has * been removed. */ + tw = intotw(inp); if (tw == NULL) goto drop; - /* tcbinfo lock required for tcp_twclose(), tcp_2msl_reset. */ - INP_INFO_WLOCK_ASSERT(&tcbinfo); - INP_LOCK_ASSERT(tw->tw_inpcb); - thflags = th->th_flags; /* @@ -3268,12 +3270,11 @@ tcp_timewait(tw, to, th, m, tlen) tcp_respond(NULL, mtod(m, void *), th, m, seq, 0, TH_RST|TH_ACK); } - INP_UNLOCK(tw->tw_inpcb); + INP_UNLOCK(inp); return (0); drop: - if (tw != NULL) - INP_UNLOCK(tw->tw_inpcb); + INP_UNLOCK(inp); m_freem(m); return (0); } diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 0532f71b5d9e..c31892ccd76d 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -173,7 +173,7 @@ static int tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *); static void tcp_xmit_timer(struct tcpcb *, int); static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); -static int tcp_timewait(struct tcptw *, struct tcpopt *, +static int tcp_timewait(struct inpcb *, struct tcpopt *, struct tcphdr *, struct mbuf *, int); /* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */ @@ -760,7 +760,7 @@ findpcb: */ if (thflags & TH_SYN) tcp_dooptions(&to, optp, optlen, 1); - if (tcp_timewait(intotw(inp), &to, th, m, tlen)) + if (tcp_timewait(inp, &to, th, m, tlen)) goto findpcb; /* * tcp_timewait unlocks inp. @@ -3141,13 +3141,14 @@ tcp_newreno_partial_ack(tp, th) * looking for a pcb in the listen state. Returns 0 otherwise. */ static int -tcp_timewait(tw, to, th, m, tlen) - struct tcptw *tw; +tcp_timewait(inp, to, th, m, tlen) + struct inpcb *inp; struct tcpopt *to; struct tcphdr *th; struct mbuf *m; int tlen; { + struct tcptw *tw; int thflags; tcp_seq seq; #ifdef INET6 @@ -3156,19 +3157,20 @@ tcp_timewait(tw, to, th, m, tlen) const int isipv6 = 0; #endif + /* tcbinfo lock required for tcp_twclose(), tcp_2msl_reset. */ + INP_INFO_WLOCK_ASSERT(&tcbinfo); + INP_LOCK_ASSERT(inp); + /* * XXXRW: Time wait state for inpcb has been recycled, but inpcb is * still present. This is undesirable, but temporarily necessary * until we work out how to handle inpcb's who's timewait state has * been removed. */ + tw = intotw(inp); if (tw == NULL) goto drop; - /* tcbinfo lock required for tcp_twclose(), tcp_2msl_reset. */ - INP_INFO_WLOCK_ASSERT(&tcbinfo); - INP_LOCK_ASSERT(tw->tw_inpcb); - thflags = th->th_flags; /* @@ -3268,12 +3270,11 @@ tcp_timewait(tw, to, th, m, tlen) tcp_respond(NULL, mtod(m, void *), th, m, seq, 0, TH_RST|TH_ACK); } - INP_UNLOCK(tw->tw_inpcb); + INP_UNLOCK(inp); return (0); drop: - if (tw != NULL) - INP_UNLOCK(tw->tw_inpcb); + INP_UNLOCK(inp); m_freem(m); return (0); }