URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [ipv4/] [tcp_timer.c] - Rev 1629
Go to most recent revision | Compare with Previous | Blame | View Log
/* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * Implementation of the Transmission Control Protocol(TCP). * * Version: @(#)tcp.c 1.0.16 05/25/93 * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Mark Evans, <evansmp@uhura.aston.ac.uk> * Corey Minyard <wf-rch!minyard@relay.EU.net> * Florian La Roche, <flla@stud.uni-sb.de> * Charles Hedrick, <hedrick@klinzhai.rutgers.edu> * Linus Torvalds, <torvalds@cs.helsinki.fi> * Alan Cox, <gw4pts@gw4pts.ampr.org> * Matthew Dillon, <dillon@apollo.west.oic.com> * Arnt Gulbrandsen, <agulbra@nvg.unit.no> * Jorge Cwik, <jorge@laser.satlink.net> * * Fixes: * * Eric Schenk : Fix retransmission timeout counting. */ #include <net/tcp.h> void tcp_delack_timer(unsigned long data) { tcp_send_ack((struct sock *) data); } /* * Reset the retransmission timer */ void tcp_reset_xmit_timer(struct sock *sk, int why, unsigned long when) { del_timer(&sk->retransmit_timer); sk->ip_xmit_timeout = why; if (why == TIME_WRITE) { /* In this case we want to timeout on the first packet * in the resend queue. If the resend queue is empty, * then the packet we are sending hasn't made it there yet, * so we timeout from the current time. */ if (sk->send_head) { sk->retransmit_timer.expires = sk->send_head->when + when; } else { /* This should never happen! */ printk(KERN_ERR "Error: send_head NULL in xmit_timer\n"); sk->ip_xmit_timeout = 0; return; } } else { sk->retransmit_timer.expires = jiffies+when; } if (sk->retransmit_timer.expires < jiffies) { /* We can get here if we reset the timer on an event * that could not fire because the interrupts were disabled. * make sure it happens soon. */ sk->retransmit_timer.expires = jiffies+2; } add_timer(&sk->retransmit_timer); } /* * POLICY: * * This is the normal code called for timeouts. It does the retransmission * and then does backoff. tcp_do_retransmit is separated out because * tcp_ack needs to send stuff from the retransmit queue without * initiating a backoff. */ static void tcp_retransmit_time(struct sock *sk, int all) { /* * record how many times we've timed out. * This determines when we should quite trying. * This needs to be counted here, because we should not be * counting one per packet we send, but rather one per round * trip timeout. */ sk->retransmits++; tcp_do_retransmit(sk, all); /* * Increase the timeout each time we retransmit. Note that * we do not increase the rtt estimate. rto is initialized * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests * that doubling rto each time is the least we can get away with. * In KA9Q, Karn uses this for the first few times, and then * goes to quadratic. netBSD doubles, but only goes up to *64, * and clamps at 1 to 64 sec afterwards. Note that 120 sec is * defined in the protocol as the maximum possible RTT. I guess * we'll have to use something other than TCP to talk to the * University of Mars. * * PAWS allows us longer timeouts and large windows, so once * implemented ftp to mars will work nicely. We will have to fix * the 120 second clamps though! */ sk->backoff++; sk->rto = min(sk->rto << 1, 120*HZ); /* be paranoid about the data structure... */ if (sk->send_head) tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto); else /* This should never happen! */ printk(KERN_ERR "send_head NULL in tcp_retransmit_time\n"); } /* * POLICY: * Congestion control. * * A timer event has trigger a tcp retransmit timeout. The * socket xmit queue is ready and set up to send. Because * the ack receive code keeps the queue straight we do * nothing clever here. */ void tcp_retransmit(struct sock *sk, int all) { if (all) { tcp_retransmit_time(sk, all); return; } /* remember window where we lost */ sk->ssthresh = min(sk->cong_window, (sk->window_seq-sk->rcv_ack_seq)/max(sk->mss,1)) >> 1; /* sk->ssthresh in theory can be zero. I guess that's OK */ sk->cong_count = 0; sk->cong_window = 1; /* Do the actual retransmit. */ tcp_retransmit_time(sk, all); } /* * A write timeout has occurred. Process the after effects. BROKEN (badly) */ static int tcp_write_timeout(struct sock *sk) { /* * Look for a 'soft' timeout. */ if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { /* * Attempt to recover if arp has changed (unlikely!) or * a route has shifted (not supported prior to 1.3). */ ip_rt_advice(&sk->ip_route_cache, 0); } /* * Have we tried to SYN too many times (repent repent 8)) * NOTE: we must be careful to do this test for both * the SYN_SENT and SYN_RECV states, otherwise we take * 23 minutes to timeout on the SYN_RECV state, which * leaves us (more) open to denial of service attacks * than we would like. */ if (sk->retransmits > TCP_SYN_RETRIES && (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV)) { if(sk->err_soft) sk->err=sk->err_soft; else sk->err=ETIMEDOUT; sk->error_report(sk); del_timer(&sk->retransmit_timer); tcp_statistics.TcpAttemptFails++; /* Is this right ??? - FIXME - */ tcp_set_state(sk,TCP_CLOSE); /* Don't FIN, we got nothing back */ return 0; } /* * Has it gone just too far ? */ if (sk->retransmits > TCP_RETR2) { if(sk->err_soft) sk->err = sk->err_soft; else sk->err = ETIMEDOUT; sk->error_report(sk); del_timer(&sk->retransmit_timer); /* * Time wait the socket */ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING ) { tcp_set_state(sk,TCP_TIME_WAIT); tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); } else { /* * Clean up time. */ tcp_set_state(sk, TCP_CLOSE); return 0; } } return 1; } /* * It could be we got here because we needed to send an ack, * so we need to check for that and not just normal retransmit. */ static void tcp_time_write_timeout(struct sock * sk) { /* * Retransmission */ sk->prot->retransmit (sk, 0); tcp_write_timeout(sk); } /* * The TCP retransmit timer. This lacks a few small details. * * 1. An initial rtt timeout on the probe0 should cause what we can * of the first write queue buffer to be split and sent. * 2. On a 'major timeout' as defined by RFC1122 we shouldn't report * ETIMEDOUT if we know an additional 'soft' error caused this. * tcp_err should save a 'soft error' for us. */ void tcp_retransmit_timer(unsigned long data) { struct sock *sk = (struct sock*)data; int why = sk->ip_xmit_timeout; /* * We are reset. We will send no more retransmits. */ if(sk->zapped) return; /* * Only process if socket is not in use */ if (sk->users) { /* Try again in 1 second */ sk->retransmit_timer.expires = jiffies+HZ; add_timer(&sk->retransmit_timer); return; } if (sk->ack_backlog && !sk->dead) sk->data_ready(sk,0); /* Now we need to figure out why the socket was on the timer. */ switch (why) { /* Window probing */ case TIME_PROBE0: tcp_send_probe0(sk); tcp_write_timeout(sk); break; /* Retransmitting */ case TIME_WRITE: tcp_time_write_timeout(sk); break; /* Sending Keepalives */ case TIME_KEEPOPEN: /* * this reset_timer() call is a hack, this is not * how KEEPOPEN is supposed to work. */ tcp_reset_xmit_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); /* Send something to keep the connection open. */ if (sk->prot->write_wakeup) sk->prot->write_wakeup (sk); sk->retransmits++; sk->prot->retransmits++; tcp_write_timeout(sk); break; default: printk (KERN_ERR "rexmit_timer: timer expired - reason unknown\n"); break; } }
Go to most recent revision | Compare with Previous | Blame | View Log