summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/in_pcb.c12
-rw-r--r--sys/netinet/tcp_subr.c19
-rw-r--r--sys/netinet/tcp_timewait.c19
-rw-r--r--sys/netinet/tcp_var.h2
4 files changed, 52 insertions, 0 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index a1490c4..ec51ad4 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -950,6 +950,7 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
* First see if this local port is in use by looking on the
* port hash list.
*/
+ retrylookup:
porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
pcbinfo->porthashmask)];
LIST_FOREACH(phd, porthash, phd_hash) {
@@ -967,6 +968,17 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
+ /*
+ * Clean out old time_wait sockets if they
+ * are clogging up needed local ports.
+ */
+ if ((inp->inp_vflag & INP_TIMEWAIT) != 0) {
+ if (tcp_twrecycleable((struct tcptw *)inp->inp_ppcb)) {
+ tcp_twclose((struct tcptw *)inp->inp_ppcb, 0);
+ match = NULL;
+ goto retrylookup;
+ }
+ }
if (inp->inp_faddr.s_addr != INADDR_ANY)
wildcard++;
if (inp->inp_laddr.s_addr != INADDR_ANY) {
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index d2a28c8..d77ab59 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1637,6 +1637,7 @@ tcp_twstart(tp)
tw->snd_nxt = tp->snd_nxt;
tw->rcv_nxt = tp->rcv_nxt;
+ tw->iss = tp->iss;
tw->cc_recv = tp->cc_recv;
tw->cc_send = tp->cc_send;
tw->t_starttime = tp->t_starttime;
@@ -1671,6 +1672,24 @@ tcp_twstart(tp)
INP_UNLOCK(inp);
}
+/*
+ * Determine if the ISN we will generate has advanced beyond the last
+ * sequence number used by the previous connection. If so, indicate
+ * that it is safe to recycle this tw socket by returning 1.
+ */
+int
+tcp_twrecycleable(struct tcptw *tw)
+{
+ tcp_seq new_isn = tw->iss;
+
+ new_isn += (ticks - tw->t_starttime) * (ISN_BYTES_PER_SECOND / hz);
+
+ if (SEQ_GT(new_isn, tw->snd_nxt))
+ return 1;
+ else
+ return 0;
+}
+
struct tcptw *
tcp_twclose(struct tcptw *tw, int reuse)
{
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index d2a28c8..d77ab59 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -1637,6 +1637,7 @@ tcp_twstart(tp)
tw->snd_nxt = tp->snd_nxt;
tw->rcv_nxt = tp->rcv_nxt;
+ tw->iss = tp->iss;
tw->cc_recv = tp->cc_recv;
tw->cc_send = tp->cc_send;
tw->t_starttime = tp->t_starttime;
@@ -1671,6 +1672,24 @@ tcp_twstart(tp)
INP_UNLOCK(inp);
}
+/*
+ * Determine if the ISN we will generate has advanced beyond the last
+ * sequence number used by the previous connection. If so, indicate
+ * that it is safe to recycle this tw socket by returning 1.
+ */
+int
+tcp_twrecycleable(struct tcptw *tw)
+{
+ tcp_seq new_isn = tw->iss;
+
+ new_isn += (ticks - tw->t_starttime) * (ISN_BYTES_PER_SECOND / hz);
+
+ if (SEQ_GT(new_isn, tw->snd_nxt))
+ return 1;
+ else
+ return 0;
+}
+
struct tcptw *
tcp_twclose(struct tcptw *tw, int reuse)
{
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 23898b9..ceb292f 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -246,6 +246,7 @@ struct tcptw {
struct inpcb *tw_inpcb; /* XXX back pointer to internet pcb */
tcp_seq snd_nxt;
tcp_seq rcv_nxt;
+ tcp_seq iss;
tcp_cc cc_recv;
tcp_cc cc_send;
u_short last_win; /* cached window value */
@@ -471,6 +472,7 @@ void tcp_canceltimers(struct tcpcb *);
struct tcpcb *
tcp_close(struct tcpcb *);
void tcp_twstart(struct tcpcb *);
+int tcp_twrecycleable(struct tcptw *tw);
struct tcptw *
tcp_twclose(struct tcptw *_tw, int _reuse);
void tcp_ctlinput(int, struct sockaddr *, void *);
OpenPOWER on IntegriCloud