diff options
-rw-r--r-- | sys/netinet/in_pcb.c | 12 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 19 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 19 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 2 |
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 *); |