162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  net/dccp/timer.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  An implementation of the DCCP protocol
662306a36Sopenharmony_ci *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/dccp.h>
1062306a36Sopenharmony_ci#include <linux/skbuff.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "dccp.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* sysctl variables governing numbers of retransmission attempts */
1662306a36Sopenharmony_ciint  sysctl_dccp_request_retries	__read_mostly = TCP_SYN_RETRIES;
1762306a36Sopenharmony_ciint  sysctl_dccp_retries1		__read_mostly = TCP_RETR1;
1862306a36Sopenharmony_ciint  sysctl_dccp_retries2		__read_mostly = TCP_RETR2;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic void dccp_write_err(struct sock *sk)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	sk->sk_err = READ_ONCE(sk->sk_err_soft) ? : ETIMEDOUT;
2362306a36Sopenharmony_ci	sk_error_report(sk);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
2662306a36Sopenharmony_ci	dccp_done(sk);
2762306a36Sopenharmony_ci	__DCCP_INC_STATS(DCCP_MIB_ABORTONTIMEOUT);
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* A write timeout has occurred. Process the after effects. */
3162306a36Sopenharmony_cistatic int dccp_write_timeout(struct sock *sk)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	const struct inet_connection_sock *icsk = inet_csk(sk);
3462306a36Sopenharmony_ci	int retry_until;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) {
3762306a36Sopenharmony_ci		if (icsk->icsk_retransmits != 0)
3862306a36Sopenharmony_ci			dst_negative_advice(sk);
3962306a36Sopenharmony_ci		retry_until = icsk->icsk_syn_retries ?
4062306a36Sopenharmony_ci			    : sysctl_dccp_request_retries;
4162306a36Sopenharmony_ci	} else {
4262306a36Sopenharmony_ci		if (icsk->icsk_retransmits >= sysctl_dccp_retries1) {
4362306a36Sopenharmony_ci			/* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu
4462306a36Sopenharmony_ci			   black hole detection. :-(
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci			   It is place to make it. It is not made. I do not want
4762306a36Sopenharmony_ci			   to make it. It is disguisting. It does not work in any
4862306a36Sopenharmony_ci			   case. Let me to cite the same draft, which requires for
4962306a36Sopenharmony_ci			   us to implement this:
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci   "The one security concern raised by this memo is that ICMP black holes
5262306a36Sopenharmony_ci   are often caused by over-zealous security administrators who block
5362306a36Sopenharmony_ci   all ICMP messages.  It is vitally important that those who design and
5462306a36Sopenharmony_ci   deploy security systems understand the impact of strict filtering on
5562306a36Sopenharmony_ci   upper-layer protocols.  The safest web site in the world is worthless
5662306a36Sopenharmony_ci   if most TCP implementations cannot transfer data from it.  It would
5762306a36Sopenharmony_ci   be far nicer to have all of the black holes fixed rather than fixing
5862306a36Sopenharmony_ci   all of the TCP implementations."
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci			   Golden words :-).
6162306a36Sopenharmony_ci		   */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci			dst_negative_advice(sk);
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		retry_until = sysctl_dccp_retries2;
6762306a36Sopenharmony_ci		/*
6862306a36Sopenharmony_ci		 * FIXME: see tcp_write_timout and tcp_out_of_resources
6962306a36Sopenharmony_ci		 */
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (icsk->icsk_retransmits >= retry_until) {
7362306a36Sopenharmony_ci		/* Has it gone just too far? */
7462306a36Sopenharmony_ci		dccp_write_err(sk);
7562306a36Sopenharmony_ci		return 1;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	return 0;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/*
8162306a36Sopenharmony_ci *	The DCCP retransmit timer.
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_cistatic void dccp_retransmit_timer(struct sock *sk)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct inet_connection_sock *icsk = inet_csk(sk);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/*
8862306a36Sopenharmony_ci	 * More than 4MSL (8 minutes) has passed, a RESET(aborted) was
8962306a36Sopenharmony_ci	 * sent, no need to retransmit, this sock is dead.
9062306a36Sopenharmony_ci	 */
9162306a36Sopenharmony_ci	if (dccp_write_timeout(sk))
9262306a36Sopenharmony_ci		return;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/*
9562306a36Sopenharmony_ci	 * We want to know the number of packets retransmitted, not the
9662306a36Sopenharmony_ci	 * total number of retransmissions of clones of original packets.
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	if (icsk->icsk_retransmits == 0)
9962306a36Sopenharmony_ci		__DCCP_INC_STATS(DCCP_MIB_TIMEOUTS);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (dccp_retransmit_skb(sk) != 0) {
10262306a36Sopenharmony_ci		/*
10362306a36Sopenharmony_ci		 * Retransmission failed because of local congestion,
10462306a36Sopenharmony_ci		 * do not backoff.
10562306a36Sopenharmony_ci		 */
10662306a36Sopenharmony_ci		if (--icsk->icsk_retransmits == 0)
10762306a36Sopenharmony_ci			icsk->icsk_retransmits = 1;
10862306a36Sopenharmony_ci		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
10962306a36Sopenharmony_ci					  min(icsk->icsk_rto,
11062306a36Sopenharmony_ci					      TCP_RESOURCE_PROBE_INTERVAL),
11162306a36Sopenharmony_ci					  DCCP_RTO_MAX);
11262306a36Sopenharmony_ci		return;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	icsk->icsk_backoff++;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
11862306a36Sopenharmony_ci	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
11962306a36Sopenharmony_ci				  DCCP_RTO_MAX);
12062306a36Sopenharmony_ci	if (icsk->icsk_retransmits > sysctl_dccp_retries1)
12162306a36Sopenharmony_ci		__sk_dst_reset(sk);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void dccp_write_timer(struct timer_list *t)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct inet_connection_sock *icsk =
12762306a36Sopenharmony_ci			from_timer(icsk, t, icsk_retransmit_timer);
12862306a36Sopenharmony_ci	struct sock *sk = &icsk->icsk_inet.sk;
12962306a36Sopenharmony_ci	int event = 0;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	bh_lock_sock(sk);
13262306a36Sopenharmony_ci	if (sock_owned_by_user(sk)) {
13362306a36Sopenharmony_ci		/* Try again later */
13462306a36Sopenharmony_ci		sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
13562306a36Sopenharmony_ci			       jiffies + (HZ / 20));
13662306a36Sopenharmony_ci		goto out;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (sk->sk_state == DCCP_CLOSED || !icsk->icsk_pending)
14062306a36Sopenharmony_ci		goto out;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (time_after(icsk->icsk_timeout, jiffies)) {
14362306a36Sopenharmony_ci		sk_reset_timer(sk, &icsk->icsk_retransmit_timer,
14462306a36Sopenharmony_ci			       icsk->icsk_timeout);
14562306a36Sopenharmony_ci		goto out;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	event = icsk->icsk_pending;
14962306a36Sopenharmony_ci	icsk->icsk_pending = 0;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	switch (event) {
15262306a36Sopenharmony_ci	case ICSK_TIME_RETRANS:
15362306a36Sopenharmony_ci		dccp_retransmit_timer(sk);
15462306a36Sopenharmony_ci		break;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ciout:
15762306a36Sopenharmony_ci	bh_unlock_sock(sk);
15862306a36Sopenharmony_ci	sock_put(sk);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void dccp_keepalive_timer(struct timer_list *t)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct sock *sk = from_timer(sk, t, sk_timer);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	pr_err("dccp should not use a keepalive timer !\n");
16662306a36Sopenharmony_ci	sock_put(sk);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/* This is the same as tcp_delack_timer, sans prequeue & mem_reclaim stuff */
17062306a36Sopenharmony_cistatic void dccp_delack_timer(struct timer_list *t)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct inet_connection_sock *icsk =
17362306a36Sopenharmony_ci			from_timer(icsk, t, icsk_delack_timer);
17462306a36Sopenharmony_ci	struct sock *sk = &icsk->icsk_inet.sk;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	bh_lock_sock(sk);
17762306a36Sopenharmony_ci	if (sock_owned_by_user(sk)) {
17862306a36Sopenharmony_ci		/* Try again later. */
17962306a36Sopenharmony_ci		__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
18062306a36Sopenharmony_ci		sk_reset_timer(sk, &icsk->icsk_delack_timer,
18162306a36Sopenharmony_ci			       jiffies + TCP_DELACK_MIN);
18262306a36Sopenharmony_ci		goto out;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (sk->sk_state == DCCP_CLOSED ||
18662306a36Sopenharmony_ci	    !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
18762306a36Sopenharmony_ci		goto out;
18862306a36Sopenharmony_ci	if (time_after(icsk->icsk_ack.timeout, jiffies)) {
18962306a36Sopenharmony_ci		sk_reset_timer(sk, &icsk->icsk_delack_timer,
19062306a36Sopenharmony_ci			       icsk->icsk_ack.timeout);
19162306a36Sopenharmony_ci		goto out;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (inet_csk_ack_scheduled(sk)) {
19762306a36Sopenharmony_ci		if (!inet_csk_in_pingpong_mode(sk)) {
19862306a36Sopenharmony_ci			/* Delayed ACK missed: inflate ATO. */
19962306a36Sopenharmony_ci			icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1,
20062306a36Sopenharmony_ci						 icsk->icsk_rto);
20162306a36Sopenharmony_ci		} else {
20262306a36Sopenharmony_ci			/* Delayed ACK missed: leave pingpong mode and
20362306a36Sopenharmony_ci			 * deflate ATO.
20462306a36Sopenharmony_ci			 */
20562306a36Sopenharmony_ci			inet_csk_exit_pingpong_mode(sk);
20662306a36Sopenharmony_ci			icsk->icsk_ack.ato = TCP_ATO_MIN;
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci		dccp_send_ack(sk);
20962306a36Sopenharmony_ci		__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS);
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ciout:
21262306a36Sopenharmony_ci	bh_unlock_sock(sk);
21362306a36Sopenharmony_ci	sock_put(sk);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/**
21762306a36Sopenharmony_ci * dccp_write_xmitlet  -  Workhorse for CCID packet dequeueing interface
21862306a36Sopenharmony_ci * @t: pointer to the tasklet associated with this handler
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * See the comments above %ccid_dequeueing_decision for supported modes.
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic void dccp_write_xmitlet(struct tasklet_struct *t)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct dccp_sock *dp = from_tasklet(dp, t, dccps_xmitlet);
22562306a36Sopenharmony_ci	struct sock *sk = &dp->dccps_inet_connection.icsk_inet.sk;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	bh_lock_sock(sk);
22862306a36Sopenharmony_ci	if (sock_owned_by_user(sk))
22962306a36Sopenharmony_ci		sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1);
23062306a36Sopenharmony_ci	else
23162306a36Sopenharmony_ci		dccp_write_xmit(sk);
23262306a36Sopenharmony_ci	bh_unlock_sock(sk);
23362306a36Sopenharmony_ci	sock_put(sk);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void dccp_write_xmit_timer(struct timer_list *t)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct dccp_sock *dp = from_timer(dp, t, dccps_xmit_timer);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	dccp_write_xmitlet(&dp->dccps_xmitlet);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_civoid dccp_init_xmit_timers(struct sock *sk)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct dccp_sock *dp = dccp_sk(sk);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	tasklet_setup(&dp->dccps_xmitlet, dccp_write_xmitlet);
24862306a36Sopenharmony_ci	timer_setup(&dp->dccps_xmit_timer, dccp_write_xmit_timer, 0);
24962306a36Sopenharmony_ci	inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer,
25062306a36Sopenharmony_ci				  &dccp_keepalive_timer);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic ktime_t dccp_timestamp_seed;
25462306a36Sopenharmony_ci/**
25562306a36Sopenharmony_ci * dccp_timestamp  -  10s of microseconds time source
25662306a36Sopenharmony_ci * Returns the number of 10s of microseconds since loading DCCP. This is native
25762306a36Sopenharmony_ci * DCCP time difference format (RFC 4340, sec. 13).
25862306a36Sopenharmony_ci * Please note: This will wrap around about circa every 11.9 hours.
25962306a36Sopenharmony_ci */
26062306a36Sopenharmony_ciu32 dccp_timestamp(void)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	u64 delta = (u64)ktime_us_delta(ktime_get_real(), dccp_timestamp_seed);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	do_div(delta, 10);
26562306a36Sopenharmony_ci	return delta;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dccp_timestamp);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_civoid __init dccp_timestamping_init(void)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	dccp_timestamp_seed = ktime_get_real();
27262306a36Sopenharmony_ci}
273