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