Add a lock around the TCPCB's sequence queue, to prevent tcp_drain()
from corrupting the queue if called from a device's interrupt context. Similar in nature to the problem reported in PR #5684.
This commit is contained in:
parent
ca15e01c76
commit
4f177aec90
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tcp_input.c,v 1.71 1998/10/08 01:19:26 thorpej Exp $ */
|
||||
/* $NetBSD: tcp_input.c,v 1.72 1998/12/18 21:38:02 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -148,6 +148,7 @@ do { \
|
|||
* when segments are out of order (so fast retransmit can work).
|
||||
*/
|
||||
#define TCP_REASS(tp, ti, m, so, flags) { \
|
||||
TCP_REASS_LOCK((tp)); \
|
||||
if ((ti)->ti_seq == (tp)->rcv_nxt && \
|
||||
(tp)->segq.lh_first == NULL && \
|
||||
(tp)->t_state == TCPS_ESTABLISHED) { \
|
||||
|
@ -162,6 +163,7 @@ do { \
|
|||
(flags) = tcp_reass((tp), (ti), (m)); \
|
||||
tp->t_flags |= TF_ACKNOW; \
|
||||
} \
|
||||
TCP_REASS_UNLOCK((tp)); \
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -178,6 +180,8 @@ tcp_reass(tp, ti, m)
|
|||
u_long rcvpartdupbyte = 0;
|
||||
u_long rcvoobyte;
|
||||
|
||||
TCP_REASS_LOCK_CHECK(tp);
|
||||
|
||||
/*
|
||||
* Call with ti==0 after become established to
|
||||
* force pre-ESTABLISHED data up to user socket.
|
||||
|
@ -858,8 +862,10 @@ after_listen:
|
|||
tp->snd_scale = tp->requested_s_scale;
|
||||
tp->rcv_scale = tp->request_r_scale;
|
||||
}
|
||||
TCP_REASS_LOCK(tp);
|
||||
(void) tcp_reass(tp, (struct tcpiphdr *)0,
|
||||
(struct mbuf *)0);
|
||||
TCP_REASS_UNLOCK(tp);
|
||||
/*
|
||||
* if we didn't have to retransmit the SYN,
|
||||
* use its rtt as our initial srtt & rtt var.
|
||||
|
@ -1124,7 +1130,9 @@ after_listen:
|
|||
tp->snd_scale = tp->requested_s_scale;
|
||||
tp->rcv_scale = tp->request_r_scale;
|
||||
}
|
||||
TCP_REASS_LOCK(tp);
|
||||
(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
|
||||
TCP_REASS_UNLOCK(tp);
|
||||
tp->snd_wl1 = ti->ti_seq - 1;
|
||||
/* fall into ... */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tcp_subr.c,v 1.62 1998/10/08 01:19:26 thorpej Exp $ */
|
||||
/* $NetBSD: tcp_subr.c,v 1.63 1998/12/18 21:38:03 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -429,7 +429,10 @@ tcp_close(tp)
|
|||
}
|
||||
#endif /* RTV_RTT */
|
||||
/* free the reassembly queue, if any */
|
||||
TCP_REASS_LOCK(tp);
|
||||
(void) tcp_freeq(tp);
|
||||
TCP_REASS_UNLOCK(tp);
|
||||
|
||||
TCP_CLEAR_DELACK(tp);
|
||||
|
||||
if (tp->t_template)
|
||||
|
@ -452,6 +455,8 @@ tcp_freeq(tp)
|
|||
int i = 0;
|
||||
#endif
|
||||
|
||||
TCP_REASS_LOCK_CHECK(tp);
|
||||
|
||||
while ((qe = tp->segq.lh_first) != NULL) {
|
||||
#ifdef TCPREASS_DEBUG
|
||||
printf("tcp_freeq[%p,%d]: %u:%u(%u) 0x%02x\n",
|
||||
|
@ -484,8 +489,16 @@ tcp_drain()
|
|||
for (; inp != (struct inpcb *)&tcbtable.inpt_queue;
|
||||
inp = inp->inp_queue.cqe_next) {
|
||||
if ((tp = intotcpcb(inp)) != NULL) {
|
||||
/*
|
||||
* We may be called from a device's interrupt
|
||||
* context. If the tcpcb is already busy,
|
||||
* just bail out now.
|
||||
*/
|
||||
if (tcp_reass_lock_try(tp) == 0)
|
||||
continue;
|
||||
if (tcp_freeq(tp))
|
||||
tcpstat.tcps_connsdrained++;
|
||||
TCP_REASS_UNLOCK(tp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: tcp_var.h,v 1.55 1998/10/06 00:20:45 matt Exp $ */
|
||||
/* $NetBSD: tcp_var.h,v 1.56 1998/12/18 21:38:03 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -107,6 +107,7 @@ struct tcpcb {
|
|||
#define TF_WILL_SACK 0x0800 /* try to use SACK */
|
||||
#define TF_CANT_TXSACK 0x1000 /* other side said I could not SACK */
|
||||
#define TF_IGNR_RXSACK 0x2000 /* ignore received SACK blocks */
|
||||
#define TF_REASSEMBLING 0x4000 /* we're busy reassembling */
|
||||
|
||||
|
||||
struct tcpiphdr *t_template; /* skeletal packet for transmit */
|
||||
|
@ -177,6 +178,67 @@ struct tcpcb {
|
|||
struct ipqehead timeq; /* time sequenced queue (for SACK) */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* TCP reassembly queue locks.
|
||||
*/
|
||||
static __inline int tcp_reass_lock_try __P((struct tcpcb *))
|
||||
__attribute__((__unused__));
|
||||
static __inline void tcp_reass_unlock __P((struct tcpcb *))
|
||||
__attribute__((__unused__));
|
||||
|
||||
static __inline int
|
||||
tcp_reass_lock_try(tp)
|
||||
struct tcpcb *tp;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splimp();
|
||||
if (tp->t_flags & TF_REASSEMBLING) {
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
tp->t_flags |= TF_REASSEMBLING;
|
||||
splx(s);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
tcp_reass_unlock(tp)
|
||||
struct tcpcb *tp;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splimp();
|
||||
tp->t_flags &= ~TF_REASSEMBLING;
|
||||
splx(s);
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
#define TCP_REASS_LOCK(tp) \
|
||||
do { \
|
||||
if (tcp_reass_lock_try(tp) == 0) { \
|
||||
printf("%s:%d: tcpcb %p reass already locked\n", \
|
||||
__FILE__, __LINE__, tp); \
|
||||
panic("tcp_reass_lock"); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TCP_REASS_LOCK_CHECK(tp) \
|
||||
do { \
|
||||
if (((tp)->t_flags & TF_REASSEMBLING) == 0) { \
|
||||
printf("%s:%d: tcpcb %p reass lock not held\n", \
|
||||
__FILE__, __LINE__, tp); \
|
||||
panic("tcp reass lock check"); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define TCP_REASS_LOCK(tp) (void) tcp_reass_lock_try((tp))
|
||||
#define TCP_REASS_LOCK_CHECK(tp) /* nothing */
|
||||
#endif
|
||||
|
||||
#define TCP_REASS_UNLOCK(tp) tcp_reass_unlock((tp))
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
* Queue for delayed ACK processing.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue