summaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_timer.c')
-rw-r--r--net/ipv4/tcp_timer.c75
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