diff options
Diffstat (limited to 'net/ipv4/tcp_timer.c')
-rw-r--r-- | net/ipv4/tcp_timer.c | 75 |
1 files changed, 55 insertions, 20 deletions
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 76ccedab2..fdf8f50ec 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.5 1998/03/03 01:23:44 ralf Exp $ + * Version: $Id: tcp_timer.c,v 1.6 1998/03/17 22:18:35 ralf Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -31,6 +31,7 @@ int sysctl_tcp_retries2 = TCP_RETR2; static void tcp_sltimer_handler(unsigned long); static void tcp_syn_recv_timer(unsigned long); static void tcp_keepalive(unsigned long data); +static void tcp_bucketgc(unsigned long); struct timer_list tcp_slow_timer = { NULL, NULL, @@ -41,7 +42,8 @@ struct timer_list tcp_slow_timer = { struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = { {ATOMIC_INIT(0), TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK */ - {ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive} /* KEEPALIVE */ + {ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}, /* KEEPALIVE */ + {ATOMIC_INIT(0), TCP_BUCKETGC_PERIOD, 0, tcp_bucketgc} /* BUCKETGC */ }; const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n"; @@ -87,20 +89,24 @@ void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when) * The delayed ack timer can be set if we are changing the * retransmit timer when removing acked frames. */ - del_timer(&tp->probe_timer); - del_timer(&tp->retransmit_timer); + if(tp->probe_timer.prev) + del_timer(&tp->probe_timer); + if(tp->retransmit_timer.prev) + del_timer(&tp->retransmit_timer); tp->retransmit_timer.expires=jiffies+when; add_timer(&tp->retransmit_timer); break; case TIME_DACK: - del_timer(&tp->delack_timer); + if(tp->delack_timer.prev) + del_timer(&tp->delack_timer); tp->delack_timer.expires=jiffies+when; add_timer(&tp->delack_timer); break; case TIME_PROBE0: - del_timer(&tp->probe_timer); + if(tp->probe_timer.prev) + del_timer(&tp->probe_timer); tp->probe_timer.expires=jiffies+when; add_timer(&tp->probe_timer); break; @@ -118,9 +124,12 @@ void tcp_clear_xmit_timers(struct sock *sk) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - del_timer(&tp->retransmit_timer); - del_timer(&tp->delack_timer); - del_timer(&tp->probe_timer); + if(tp->retransmit_timer.prev) + del_timer(&tp->retransmit_timer); + if(tp->delack_timer.prev) + del_timer(&tp->delack_timer); + if(tp->probe_timer.prev) + del_timer(&tp->probe_timer); } static int tcp_write_err(struct sock *sk, int force) @@ -131,9 +140,8 @@ static int tcp_write_err(struct sock *sk, int force) tcp_clear_xmit_timers(sk); /* Time wait the socket. */ - if (!force && (1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) { - tcp_set_state(sk,TCP_TIME_WAIT); - tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + if (!force && ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) { + tcp_time_wait(sk); } else { /* Clean up time. */ tcp_set_state(sk, TCP_CLOSE); @@ -173,9 +181,8 @@ static int tcp_write_timeout(struct sock *sk) return 1; } - -void tcp_delack_timer(unsigned long data) { - +void tcp_delack_timer(unsigned long data) +{ struct sock *sk = (struct sock*)data; if(sk->zapped) @@ -185,8 +192,8 @@ void tcp_delack_timer(unsigned long data) { tcp_read_wakeup(sk); } -void tcp_probe_timer(unsigned long data) { - +void tcp_probe_timer(unsigned long data) +{ struct sock *sk = (struct sock*)data; struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; @@ -212,10 +219,9 @@ void tcp_probe_timer(unsigned long data) { sk->err = ETIMEDOUT; sk->error_report(sk); - /* Time wait the socket. */ if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) { - tcp_set_state(sk, TCP_TIME_WAIT); - tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + /* Time wait the socket. */ + tcp_time_wait(sk); } else { /* Clean up time. */ tcp_set_state(sk, TCP_CLOSE); @@ -252,6 +258,35 @@ static __inline__ int tcp_keepopen_proc(struct sock *sk) return res; } +/* Garbage collect TCP bind buckets. */ +static void tcp_bucketgc(unsigned long __unused) +{ + int i; + + for(i = 0; i < TCP_BHTABLE_SIZE; i++) { + struct tcp_bind_bucket *tb = tcp_bound_hash[i]; + + while(tb) { + struct tcp_bind_bucket *next = tb->next; + + if((tb->owners == NULL) && + !(tb->flags & TCPB_FLAG_LOCKED)) { + /* Eat timer reference. */ + tcp_dec_slow_timer(TCP_SLT_BUCKETGC); + + /* Unlink bucket. */ + if(tb->next) + tb->next->pprev = tb->pprev; + *tb->pprev = tb->next; + + /* Finally, free it up. */ + kmem_cache_free(tcp_bucket_cachep, tb); + } + tb = next; + } + } +} + /* * Check all sockets for keepalive timer * Called every 75 seconds |