Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | /*
* 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;
}
}
|