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