xref: /openbmc/linux/net/dccp/timer.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27c657876SArnaldo Carvalho de Melo /*
37c657876SArnaldo Carvalho de Melo  *  net/dccp/timer.c
47c657876SArnaldo Carvalho de Melo  *
57c657876SArnaldo Carvalho de Melo  *  An implementation of the DCCP protocol
67c657876SArnaldo Carvalho de Melo  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
77c657876SArnaldo Carvalho de Melo  */
87c657876SArnaldo Carvalho de Melo 
97c657876SArnaldo Carvalho de Melo #include <linux/dccp.h>
107c657876SArnaldo Carvalho de Melo #include <linux/skbuff.h>
11bc3b2d7fSPaul Gortmaker #include <linux/export.h>
127c657876SArnaldo Carvalho de Melo 
137c657876SArnaldo Carvalho de Melo #include "dccp.h"
147c657876SArnaldo Carvalho de Melo 
152e2e9e92SGerrit Renker /* sysctl variables governing numbers of retransmission attempts */
162e2e9e92SGerrit Renker int  sysctl_dccp_request_retries	__read_mostly = TCP_SYN_RETRIES;
172e2e9e92SGerrit Renker int  sysctl_dccp_retries1		__read_mostly = TCP_RETR1;
182e2e9e92SGerrit Renker int  sysctl_dccp_retries2		__read_mostly = TCP_RETR2;
192e2e9e92SGerrit Renker 
dccp_write_err(struct sock * sk)207c657876SArnaldo Carvalho de Melo static void dccp_write_err(struct sock *sk)
217c657876SArnaldo Carvalho de Melo {
22*9a25f0cbSEric Dumazet 	sk->sk_err = READ_ONCE(sk->sk_err_soft) ? : ETIMEDOUT;
23e3ae2365SAlexander Aring 	sk_error_report(sk);
247c657876SArnaldo Carvalho de Melo 
25017487d7SArnaldo Carvalho de Melo 	dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
267c657876SArnaldo Carvalho de Melo 	dccp_done(sk);
27aa62d76bSEric Dumazet 	__DCCP_INC_STATS(DCCP_MIB_ABORTONTIMEOUT);
287c657876SArnaldo Carvalho de Melo }
297c657876SArnaldo Carvalho de Melo 
307c657876SArnaldo Carvalho de Melo /* A write timeout has occurred. Process the after effects. */
dccp_write_timeout(struct sock * sk)317c657876SArnaldo Carvalho de Melo static int dccp_write_timeout(struct sock *sk)
327c657876SArnaldo Carvalho de Melo {
337c657876SArnaldo Carvalho de Melo 	const struct inet_connection_sock *icsk = inet_csk(sk);
347c657876SArnaldo Carvalho de Melo 	int retry_until;
357c657876SArnaldo Carvalho de Melo 
367c657876SArnaldo Carvalho de Melo 	if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) {
377c657876SArnaldo Carvalho de Melo 		if (icsk->icsk_retransmits != 0)
38b6c6712aSEric Dumazet 			dst_negative_advice(sk);
392e2e9e92SGerrit Renker 		retry_until = icsk->icsk_syn_retries ?
402e2e9e92SGerrit Renker 			    : sysctl_dccp_request_retries;
417c657876SArnaldo Carvalho de Melo 	} else {
422e2e9e92SGerrit Renker 		if (icsk->icsk_retransmits >= sysctl_dccp_retries1) {
437690af3fSArnaldo Carvalho de Melo 			/* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu
447690af3fSArnaldo Carvalho de Melo 			   black hole detection. :-(
457c657876SArnaldo Carvalho de Melo 
467c657876SArnaldo Carvalho de Melo 			   It is place to make it. It is not made. I do not want
477c657876SArnaldo Carvalho de Melo 			   to make it. It is disguisting. It does not work in any
487c657876SArnaldo Carvalho de Melo 			   case. Let me to cite the same draft, which requires for
497c657876SArnaldo Carvalho de Melo 			   us to implement this:
507c657876SArnaldo Carvalho de Melo 
517c657876SArnaldo Carvalho de Melo    "The one security concern raised by this memo is that ICMP black holes
527c657876SArnaldo Carvalho de Melo    are often caused by over-zealous security administrators who block
537c657876SArnaldo Carvalho de Melo    all ICMP messages.  It is vitally important that those who design and
547c657876SArnaldo Carvalho de Melo    deploy security systems understand the impact of strict filtering on
557c657876SArnaldo Carvalho de Melo    upper-layer protocols.  The safest web site in the world is worthless
567c657876SArnaldo Carvalho de Melo    if most TCP implementations cannot transfer data from it.  It would
577c657876SArnaldo Carvalho de Melo    be far nicer to have all of the black holes fixed rather than fixing
587c657876SArnaldo Carvalho de Melo    all of the TCP implementations."
597c657876SArnaldo Carvalho de Melo 
607c657876SArnaldo Carvalho de Melo 			   Golden words :-).
617c657876SArnaldo Carvalho de Melo 		   */
627c657876SArnaldo Carvalho de Melo 
63b6c6712aSEric Dumazet 			dst_negative_advice(sk);
647c657876SArnaldo Carvalho de Melo 		}
657c657876SArnaldo Carvalho de Melo 
662e2e9e92SGerrit Renker 		retry_until = sysctl_dccp_retries2;
677c657876SArnaldo Carvalho de Melo 		/*
687c657876SArnaldo Carvalho de Melo 		 * FIXME: see tcp_write_timout and tcp_out_of_resources
697c657876SArnaldo Carvalho de Melo 		 */
707c657876SArnaldo Carvalho de Melo 	}
717c657876SArnaldo Carvalho de Melo 
727c657876SArnaldo Carvalho de Melo 	if (icsk->icsk_retransmits >= retry_until) {
737c657876SArnaldo Carvalho de Melo 		/* Has it gone just too far? */
747c657876SArnaldo Carvalho de Melo 		dccp_write_err(sk);
757c657876SArnaldo Carvalho de Melo 		return 1;
767c657876SArnaldo Carvalho de Melo 	}
777c657876SArnaldo Carvalho de Melo 	return 0;
787c657876SArnaldo Carvalho de Melo }
797c657876SArnaldo Carvalho de Melo 
807c657876SArnaldo Carvalho de Melo /*
817c657876SArnaldo Carvalho de Melo  *	The DCCP retransmit timer.
827c657876SArnaldo Carvalho de Melo  */
dccp_retransmit_timer(struct sock * sk)837c657876SArnaldo Carvalho de Melo static void dccp_retransmit_timer(struct sock *sk)
847c657876SArnaldo Carvalho de Melo {
857c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
867c657876SArnaldo Carvalho de Melo 
877c657876SArnaldo Carvalho de Melo 	/*
8854633527SRandy Dunlap 	 * More than 4MSL (8 minutes) has passed, a RESET(aborted) was
897c657876SArnaldo Carvalho de Melo 	 * sent, no need to retransmit, this sock is dead.
907c657876SArnaldo Carvalho de Melo 	 */
917c657876SArnaldo Carvalho de Melo 	if (dccp_write_timeout(sk))
9259435444SGerrit Renker 		return;
937c657876SArnaldo Carvalho de Melo 
947c657876SArnaldo Carvalho de Melo 	/*
957c657876SArnaldo Carvalho de Melo 	 * We want to know the number of packets retransmitted, not the
967c657876SArnaldo Carvalho de Melo 	 * total number of retransmissions of clones of original packets.
977c657876SArnaldo Carvalho de Melo 	 */
987c657876SArnaldo Carvalho de Melo 	if (icsk->icsk_retransmits == 0)
99aa62d76bSEric Dumazet 		__DCCP_INC_STATS(DCCP_MIB_TIMEOUTS);
1007c657876SArnaldo Carvalho de Melo 
10159435444SGerrit Renker 	if (dccp_retransmit_skb(sk) != 0) {
1027c657876SArnaldo Carvalho de Melo 		/*
1037c657876SArnaldo Carvalho de Melo 		 * Retransmission failed because of local congestion,
1047c657876SArnaldo Carvalho de Melo 		 * do not backoff.
1057c657876SArnaldo Carvalho de Melo 		 */
10659435444SGerrit Renker 		if (--icsk->icsk_retransmits == 0)
1077c657876SArnaldo Carvalho de Melo 			icsk->icsk_retransmits = 1;
1087c657876SArnaldo Carvalho de Melo 		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
1097c657876SArnaldo Carvalho de Melo 					  min(icsk->icsk_rto,
1107c657876SArnaldo Carvalho de Melo 					      TCP_RESOURCE_PROBE_INTERVAL),
1117690af3fSArnaldo Carvalho de Melo 					  DCCP_RTO_MAX);
11259435444SGerrit Renker 		return;
1137c657876SArnaldo Carvalho de Melo 	}
1147c657876SArnaldo Carvalho de Melo 
1157c657876SArnaldo Carvalho de Melo 	icsk->icsk_backoff++;
1167c657876SArnaldo Carvalho de Melo 
1177c657876SArnaldo Carvalho de Melo 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
1187690af3fSArnaldo Carvalho de Melo 	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
1197690af3fSArnaldo Carvalho de Melo 				  DCCP_RTO_MAX);
1202e2e9e92SGerrit Renker 	if (icsk->icsk_retransmits > sysctl_dccp_retries1)
1217c657876SArnaldo Carvalho de Melo 		__sk_dst_reset(sk);
1227c657876SArnaldo Carvalho de Melo }
1237c657876SArnaldo Carvalho de Melo 
dccp_write_timer(struct timer_list * t)12459f379f9SKees Cook static void dccp_write_timer(struct timer_list *t)
1257c657876SArnaldo Carvalho de Melo {
12659f379f9SKees Cook 	struct inet_connection_sock *icsk =
12759f379f9SKees Cook 			from_timer(icsk, t, icsk_retransmit_timer);
12859f379f9SKees Cook 	struct sock *sk = &icsk->icsk_inet.sk;
1297c657876SArnaldo Carvalho de Melo 	int event = 0;
1307c657876SArnaldo Carvalho de Melo 
1317c657876SArnaldo Carvalho de Melo 	bh_lock_sock(sk);
1327c657876SArnaldo Carvalho de Melo 	if (sock_owned_by_user(sk)) {
1337c657876SArnaldo Carvalho de Melo 		/* Try again later */
1347690af3fSArnaldo Carvalho de Melo 		sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
1357690af3fSArnaldo Carvalho de Melo 			       jiffies + (HZ / 20));
1367c657876SArnaldo Carvalho de Melo 		goto out;
1377c657876SArnaldo Carvalho de Melo 	}
1387c657876SArnaldo Carvalho de Melo 
1397c657876SArnaldo Carvalho de Melo 	if (sk->sk_state == DCCP_CLOSED || !icsk->icsk_pending)
1407c657876SArnaldo Carvalho de Melo 		goto out;
1417c657876SArnaldo Carvalho de Melo 
1427c657876SArnaldo Carvalho de Melo 	if (time_after(icsk->icsk_timeout, jiffies)) {
1437690af3fSArnaldo Carvalho de Melo 		sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
1447690af3fSArnaldo Carvalho de Melo 			       icsk->icsk_timeout);
1457c657876SArnaldo Carvalho de Melo 		goto out;
1467c657876SArnaldo Carvalho de Melo 	}
1477c657876SArnaldo Carvalho de Melo 
1487c657876SArnaldo Carvalho de Melo 	event = icsk->icsk_pending;
1497c657876SArnaldo Carvalho de Melo 	icsk->icsk_pending = 0;
1507c657876SArnaldo Carvalho de Melo 
1517c657876SArnaldo Carvalho de Melo 	switch (event) {
1527c657876SArnaldo Carvalho de Melo 	case ICSK_TIME_RETRANS:
1537c657876SArnaldo Carvalho de Melo 		dccp_retransmit_timer(sk);
1547c657876SArnaldo Carvalho de Melo 		break;
1557c657876SArnaldo Carvalho de Melo 	}
1567c657876SArnaldo Carvalho de Melo out:
1577c657876SArnaldo Carvalho de Melo 	bh_unlock_sock(sk);
1587c657876SArnaldo Carvalho de Melo 	sock_put(sk);
1597c657876SArnaldo Carvalho de Melo }
1607c657876SArnaldo Carvalho de Melo 
dccp_keepalive_timer(struct timer_list * t)16159f379f9SKees Cook static void dccp_keepalive_timer(struct timer_list *t)
1627c657876SArnaldo Carvalho de Melo {
16359f379f9SKees Cook 	struct sock *sk = from_timer(sk, t, sk_timer);
1647c657876SArnaldo Carvalho de Melo 
165fa76ce73SEric Dumazet 	pr_err("dccp should not use a keepalive timer !\n");
1667c657876SArnaldo Carvalho de Melo 	sock_put(sk);
1677c657876SArnaldo Carvalho de Melo }
1684ed800d0SGerrit Renker 
1694ed800d0SGerrit Renker /* This is the same as tcp_delack_timer, sans prequeue & mem_reclaim stuff */
dccp_delack_timer(struct timer_list * t)17059f379f9SKees Cook static void dccp_delack_timer(struct timer_list *t)
1714ed800d0SGerrit Renker {
17259f379f9SKees Cook 	struct inet_connection_sock *icsk =
17359f379f9SKees Cook 			from_timer(icsk, t, icsk_delack_timer);
17459f379f9SKees Cook 	struct sock *sk = &icsk->icsk_inet.sk;
1754ed800d0SGerrit Renker 
1764ed800d0SGerrit Renker 	bh_lock_sock(sk);
1774ed800d0SGerrit Renker 	if (sock_owned_by_user(sk)) {
1784ed800d0SGerrit Renker 		/* Try again later. */
17902a1d6e7SEric Dumazet 		__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
1804ed800d0SGerrit Renker 		sk_reset_timer(sk, &icsk->icsk_delack_timer,
1814ed800d0SGerrit Renker 			       jiffies + TCP_DELACK_MIN);
1824ed800d0SGerrit Renker 		goto out;
1834ed800d0SGerrit Renker 	}
1844ed800d0SGerrit Renker 
1854ed800d0SGerrit Renker 	if (sk->sk_state == DCCP_CLOSED ||
1864ed800d0SGerrit Renker 	    !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
1874ed800d0SGerrit Renker 		goto out;
1884ed800d0SGerrit Renker 	if (time_after(icsk->icsk_ack.timeout, jiffies)) {
1894ed800d0SGerrit Renker 		sk_reset_timer(sk, &icsk->icsk_delack_timer,
1904ed800d0SGerrit Renker 			       icsk->icsk_ack.timeout);
1914ed800d0SGerrit Renker 		goto out;
1924ed800d0SGerrit Renker 	}
1934ed800d0SGerrit Renker 
1944ed800d0SGerrit Renker 	icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
1954ed800d0SGerrit Renker 
1964ed800d0SGerrit Renker 	if (inet_csk_ack_scheduled(sk)) {
19731954cd8SWei Wang 		if (!inet_csk_in_pingpong_mode(sk)) {
1984ed800d0SGerrit Renker 			/* Delayed ACK missed: inflate ATO. */
1994ed800d0SGerrit Renker 			icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1,
2004ed800d0SGerrit Renker 						 icsk->icsk_rto);
2014ed800d0SGerrit Renker 		} else {
2024ed800d0SGerrit Renker 			/* Delayed ACK missed: leave pingpong mode and
2034ed800d0SGerrit Renker 			 * deflate ATO.
2044ed800d0SGerrit Renker 			 */
20531954cd8SWei Wang 			inet_csk_exit_pingpong_mode(sk);
2064ed800d0SGerrit Renker 			icsk->icsk_ack.ato = TCP_ATO_MIN;
2074ed800d0SGerrit Renker 		}
2084ed800d0SGerrit Renker 		dccp_send_ack(sk);
20902a1d6e7SEric Dumazet 		__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS);
2104ed800d0SGerrit Renker 	}
2114ed800d0SGerrit Renker out:
2124ed800d0SGerrit Renker 	bh_unlock_sock(sk);
2134ed800d0SGerrit Renker 	sock_put(sk);
2144ed800d0SGerrit Renker }
2154ed800d0SGerrit Renker 
216dc841e30SGerrit Renker /**
217dc841e30SGerrit Renker  * dccp_write_xmitlet  -  Workhorse for CCID packet dequeueing interface
218fccf290fSAllen Pais  * @t: pointer to the tasklet associated with this handler
219d0b1101bSAndrew Lunn  *
220dc841e30SGerrit Renker  * See the comments above %ccid_dequeueing_decision for supported modes.
221dc841e30SGerrit Renker  */
dccp_write_xmitlet(struct tasklet_struct * t)222fccf290fSAllen Pais static void dccp_write_xmitlet(struct tasklet_struct *t)
223aabb601bSGerrit Renker {
224fccf290fSAllen Pais 	struct dccp_sock *dp = from_tasklet(dp, t, dccps_xmitlet);
225fccf290fSAllen Pais 	struct sock *sk = &dp->dccps_inet_connection.icsk_inet.sk;
226aabb601bSGerrit Renker 
227aabb601bSGerrit Renker 	bh_lock_sock(sk);
228aabb601bSGerrit Renker 	if (sock_owned_by_user(sk))
229dc841e30SGerrit Renker 		sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1);
230aabb601bSGerrit Renker 	else
231b1fcf55eSGerrit Renker 		dccp_write_xmit(sk);
232aabb601bSGerrit Renker 	bh_unlock_sock(sk);
233a8d7aa17SEric Dumazet 	sock_put(sk);
234aabb601bSGerrit Renker }
235aabb601bSGerrit Renker 
dccp_write_xmit_timer(struct timer_list * t)236839a6094SKees Cook static void dccp_write_xmit_timer(struct timer_list *t)
237aabb601bSGerrit Renker {
238839a6094SKees Cook 	struct dccp_sock *dp = from_timer(dp, t, dccps_xmit_timer);
239839a6094SKees Cook 
240fccf290fSAllen Pais 	dccp_write_xmitlet(&dp->dccps_xmitlet);
241aabb601bSGerrit Renker }
242aabb601bSGerrit Renker 
dccp_init_xmit_timers(struct sock * sk)2434ed800d0SGerrit Renker void dccp_init_xmit_timers(struct sock *sk)
2444ed800d0SGerrit Renker {
245dc841e30SGerrit Renker 	struct dccp_sock *dp = dccp_sk(sk);
246dc841e30SGerrit Renker 
247fccf290fSAllen Pais 	tasklet_setup(&dp->dccps_xmitlet, dccp_write_xmitlet);
248839a6094SKees Cook 	timer_setup(&dp->dccps_xmit_timer, dccp_write_xmit_timer, 0);
2494ed800d0SGerrit Renker 	inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer,
2504ed800d0SGerrit Renker 				  &dccp_keepalive_timer);
2514ed800d0SGerrit Renker }
2524c70f383SGerrit Renker 
2534c70f383SGerrit Renker static ktime_t dccp_timestamp_seed;
2544c70f383SGerrit Renker /**
2554c70f383SGerrit Renker  * dccp_timestamp  -  10s of microseconds time source
2564c70f383SGerrit Renker  * Returns the number of 10s of microseconds since loading DCCP. This is native
2574c70f383SGerrit Renker  * DCCP time difference format (RFC 4340, sec. 13).
2584c70f383SGerrit Renker  * Please note: This will wrap around about circa every 11.9 hours.
2594c70f383SGerrit Renker  */
dccp_timestamp(void)2604c70f383SGerrit Renker u32 dccp_timestamp(void)
2614c70f383SGerrit Renker {
2625c4a43b0SChen Gang 	u64 delta = (u64)ktime_us_delta(ktime_get_real(), dccp_timestamp_seed);
2634c70f383SGerrit Renker 
2644c70f383SGerrit Renker 	do_div(delta, 10);
2654c70f383SGerrit Renker 	return delta;
2664c70f383SGerrit Renker }
2674c70f383SGerrit Renker EXPORT_SYMBOL_GPL(dccp_timestamp);
2684c70f383SGerrit Renker 
dccp_timestamping_init(void)2694c70f383SGerrit Renker void __init dccp_timestamping_init(void)
2704c70f383SGerrit Renker {
2714c70f383SGerrit Renker 	dccp_timestamp_seed = ktime_get_real();
2724c70f383SGerrit Renker }
273