Blame view

net/dccp/timer.c 7.52 KB
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
1
2
  /*
   *  net/dccp/timer.c
8109b02b5   Arnaldo Carvalho de Melo   [DCCP]: Whitespac...
3
   *
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
4
5
6
7
8
9
10
11
   *  An implementation of the DCCP protocol
   *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   */
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
12
13
  #include <linux/dccp.h>
  #include <linux/skbuff.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
14
  #include <linux/export.h>
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
15
16
  
  #include "dccp.h"
2e2e9e92b   Gerrit Renker   [DCCP]: Add sysct...
17
18
19
20
  /* sysctl variables governing numbers of retransmission attempts */
  int  sysctl_dccp_request_retries	__read_mostly = TCP_SYN_RETRIES;
  int  sysctl_dccp_retries1		__read_mostly = TCP_RETR1;
  int  sysctl_dccp_retries2		__read_mostly = TCP_RETR2;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
21
22
23
24
  static void dccp_write_err(struct sock *sk)
  {
  	sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
  	sk->sk_error_report(sk);
017487d7d   Arnaldo Carvalho de Melo   [DCCP]: Generaliz...
25
  	dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
26
27
28
29
30
31
32
33
34
35
36
37
  	dccp_done(sk);
  	DCCP_INC_STATS_BH(DCCP_MIB_ABORTONTIMEOUT);
  }
  
  /* A write timeout has occurred. Process the after effects. */
  static int dccp_write_timeout(struct sock *sk)
  {
  	const struct inet_connection_sock *icsk = inet_csk(sk);
  	int retry_until;
  
  	if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) {
  		if (icsk->icsk_retransmits != 0)
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
38
  			dst_negative_advice(sk);
2e2e9e92b   Gerrit Renker   [DCCP]: Add sysct...
39
40
  		retry_until = icsk->icsk_syn_retries ?
  			    : sysctl_dccp_request_retries;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
41
  	} else {
2e2e9e92b   Gerrit Renker   [DCCP]: Add sysct...
42
  		if (icsk->icsk_retransmits >= sysctl_dccp_retries1) {
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
43
44
  			/* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu
  			   black hole detection. :-(
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  
  			   It is place to make it. It is not made. I do not want
  			   to make it. It is disguisting. It does not work in any
  			   case. Let me to cite the same draft, which requires for
  			   us to implement this:
  
     "The one security concern raised by this memo is that ICMP black holes
     are often caused by over-zealous security administrators who block
     all ICMP messages.  It is vitally important that those who design and
     deploy security systems understand the impact of strict filtering on
     upper-layer protocols.  The safest web site in the world is worthless
     if most TCP implementations cannot transfer data from it.  It would
     be far nicer to have all of the black holes fixed rather than fixing
     all of the TCP implementations."
c9eaf1734   YOSHIFUJI Hideaki   [NET] DCCP: Fix w...
59
  			   Golden words :-).
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
60
  		   */
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
61
  			dst_negative_advice(sk);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
62
  		}
2e2e9e92b   Gerrit Renker   [DCCP]: Add sysct...
63
  		retry_until = sysctl_dccp_retries2;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
64
65
66
67
68
69
70
71
72
73
74
75
  		/*
  		 * FIXME: see tcp_write_timout and tcp_out_of_resources
  		 */
  	}
  
  	if (icsk->icsk_retransmits >= retry_until) {
  		/* Has it gone just too far? */
  		dccp_write_err(sk);
  		return 1;
  	}
  	return 0;
  }
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
76
77
78
79
80
81
82
83
  /*
   *	The DCCP retransmit timer.
   */
  static void dccp_retransmit_timer(struct sock *sk)
  {
  	struct inet_connection_sock *icsk = inet_csk(sk);
  
  	/*
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
84
85
86
87
  	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
  	 * sent, no need to retransmit, this sock is dead.
  	 */
  	if (dccp_write_timeout(sk))
59435444a   Gerrit Renker   dccp: Allow to di...
88
  		return;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
89
90
91
92
93
94
95
  
  	/*
  	 * We want to know the number of packets retransmitted, not the
  	 * total number of retransmissions of clones of original packets.
  	 */
  	if (icsk->icsk_retransmits == 0)
  		DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS);
59435444a   Gerrit Renker   dccp: Allow to di...
96
  	if (dccp_retransmit_skb(sk) != 0) {
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
97
98
99
100
  		/*
  		 * Retransmission failed because of local congestion,
  		 * do not backoff.
  		 */
59435444a   Gerrit Renker   dccp: Allow to di...
101
  		if (--icsk->icsk_retransmits == 0)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
102
103
104
105
  			icsk->icsk_retransmits = 1;
  		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
  					  min(icsk->icsk_rto,
  					      TCP_RESOURCE_PROBE_INTERVAL),
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
106
  					  DCCP_RTO_MAX);
59435444a   Gerrit Renker   dccp: Allow to di...
107
  		return;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
108
109
110
  	}
  
  	icsk->icsk_backoff++;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
111
112
  
  	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
113
114
  	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
  				  DCCP_RTO_MAX);
2e2e9e92b   Gerrit Renker   [DCCP]: Add sysct...
115
  	if (icsk->icsk_retransmits > sysctl_dccp_retries1)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
116
  		__sk_dst_reset(sk);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
117
118
119
120
121
122
123
124
125
126
127
  }
  
  static void dccp_write_timer(unsigned long data)
  {
  	struct sock *sk = (struct sock *)data;
  	struct inet_connection_sock *icsk = inet_csk(sk);
  	int event = 0;
  
  	bh_lock_sock(sk);
  	if (sock_owned_by_user(sk)) {
  		/* Try again later */
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
128
129
  		sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
  			       jiffies + (HZ / 20));
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
130
131
132
133
134
135
136
  		goto out;
  	}
  
  	if (sk->sk_state == DCCP_CLOSED || !icsk->icsk_pending)
  		goto out;
  
  	if (time_after(icsk->icsk_timeout, jiffies)) {
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
137
138
  		sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
  			       icsk->icsk_timeout);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  		goto out;
  	}
  
  	event = icsk->icsk_pending;
  	icsk->icsk_pending = 0;
  
  	switch (event) {
  	case ICSK_TIME_RETRANS:
  		dccp_retransmit_timer(sk);
  		break;
  	}
  out:
  	bh_unlock_sock(sk);
  	sock_put(sk);
  }
  
  /*
   *	Timer for listening sockets
   */
  static void dccp_response_timer(struct sock *sk)
  {
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
160
161
  	inet_csk_reqsk_queue_prune(sk, TCP_SYNQ_INTERVAL, DCCP_TIMEOUT_INIT,
  				   DCCP_RTO_MAX);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
162
163
164
165
166
167
168
169
170
  }
  
  static void dccp_keepalive_timer(unsigned long data)
  {
  	struct sock *sk = (struct sock *)data;
  
  	/* Only process if socket is not in use. */
  	bh_lock_sock(sk);
  	if (sock_owned_by_user(sk)) {
8109b02b5   Arnaldo Carvalho de Melo   [DCCP]: Whitespac...
171
  		/* Try again later. */
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
172
173
174
175
176
177
178
179
180
181
182
183
  		inet_csk_reset_keepalive_timer(sk, HZ / 20);
  		goto out;
  	}
  
  	if (sk->sk_state == DCCP_LISTEN) {
  		dccp_response_timer(sk);
  		goto out;
  	}
  out:
  	bh_unlock_sock(sk);
  	sock_put(sk);
  }
4ed800d02   Gerrit Renker   [DCCP]: Remove fo...
184
185
186
187
188
189
190
191
192
193
194
  
  /* This is the same as tcp_delack_timer, sans prequeue & mem_reclaim stuff */
  static void dccp_delack_timer(unsigned long data)
  {
  	struct sock *sk = (struct sock *)data;
  	struct inet_connection_sock *icsk = inet_csk(sk);
  
  	bh_lock_sock(sk);
  	if (sock_owned_by_user(sk)) {
  		/* Try again later. */
  		icsk->icsk_ack.blocked = 1;
de0744af1   Pavel Emelyanov   mib: add net to N...
195
  		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
4ed800d02   Gerrit Renker   [DCCP]: Remove fo...
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
  		sk_reset_timer(sk, &icsk->icsk_delack_timer,
  			       jiffies + TCP_DELACK_MIN);
  		goto out;
  	}
  
  	if (sk->sk_state == DCCP_CLOSED ||
  	    !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
  		goto out;
  	if (time_after(icsk->icsk_ack.timeout, jiffies)) {
  		sk_reset_timer(sk, &icsk->icsk_delack_timer,
  			       icsk->icsk_ack.timeout);
  		goto out;
  	}
  
  	icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
  
  	if (inet_csk_ack_scheduled(sk)) {
  		if (!icsk->icsk_ack.pingpong) {
  			/* Delayed ACK missed: inflate ATO. */
  			icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1,
  						 icsk->icsk_rto);
  		} else {
  			/* Delayed ACK missed: leave pingpong mode and
  			 * deflate ATO.
  			 */
  			icsk->icsk_ack.pingpong = 0;
  			icsk->icsk_ack.ato = TCP_ATO_MIN;
  		}
  		dccp_send_ack(sk);
de0744af1   Pavel Emelyanov   mib: add net to N...
225
  		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKS);
4ed800d02   Gerrit Renker   [DCCP]: Remove fo...
226
227
228
229
230
  	}
  out:
  	bh_unlock_sock(sk);
  	sock_put(sk);
  }
dc841e30e   Gerrit Renker   dccp: Extend CCID...
231
232
233
234
235
  /**
   * dccp_write_xmitlet  -  Workhorse for CCID packet dequeueing interface
   * See the comments above %ccid_dequeueing_decision for supported modes.
   */
  static void dccp_write_xmitlet(unsigned long data)
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
236
237
  {
  	struct sock *sk = (struct sock *)data;
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
238
239
240
  
  	bh_lock_sock(sk);
  	if (sock_owned_by_user(sk))
dc841e30e   Gerrit Renker   dccp: Extend CCID...
241
  		sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1);
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
242
  	else
b1fcf55ee   Gerrit Renker   dccp: Refine the ...
243
  		dccp_write_xmit(sk);
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
244
  	bh_unlock_sock(sk);
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
245
  }
dc841e30e   Gerrit Renker   dccp: Extend CCID...
246
  static void dccp_write_xmit_timer(unsigned long data)
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
247
  {
dc841e30e   Gerrit Renker   dccp: Extend CCID...
248
249
  	dccp_write_xmitlet(data);
  	sock_put((struct sock *)data);
aabb601b0   Gerrit Renker   [DCCP]: Initialis...
250
  }
4ed800d02   Gerrit Renker   [DCCP]: Remove fo...
251
252
  void dccp_init_xmit_timers(struct sock *sk)
  {
dc841e30e   Gerrit Renker   dccp: Extend CCID...
253
254
255
256
257
  	struct dccp_sock *dp = dccp_sk(sk);
  
  	tasklet_init(&dp->dccps_xmitlet, dccp_write_xmitlet, (unsigned long)sk);
  	setup_timer(&dp->dccps_xmit_timer, dccp_write_xmit_timer,
  							     (unsigned long)sk);
4ed800d02   Gerrit Renker   [DCCP]: Remove fo...
258
259
260
  	inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer,
  				  &dccp_keepalive_timer);
  }
4c70f383e   Gerrit Renker   [DCCP]: Provide 1...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  
  static ktime_t dccp_timestamp_seed;
  /**
   * dccp_timestamp  -  10s of microseconds time source
   * Returns the number of 10s of microseconds since loading DCCP. This is native
   * DCCP time difference format (RFC 4340, sec. 13).
   * Please note: This will wrap around about circa every 11.9 hours.
   */
  u32 dccp_timestamp(void)
  {
  	s64 delta = ktime_us_delta(ktime_get_real(), dccp_timestamp_seed);
  
  	do_div(delta, 10);
  	return delta;
  }
  EXPORT_SYMBOL_GPL(dccp_timestamp);
  
  void __init dccp_timestamping_init(void)
  {
  	dccp_timestamp_seed = ktime_get_real();
  }