#define ICSK_TIME_PROBE0       3       /* Zero window probe timer */
 #define ICSK_TIME_EARLY_RETRANS 4      /* Early retransmit timer */
 #define ICSK_TIME_LOSS_PROBE   5       /* Tail loss probe timer */
+#define ICSK_TIME_REO_TIMEOUT  6       /* Reordering timer */
 
 static inline struct inet_connection_sock *inet_csk(const struct sock *sk)
 {
        }
 
        if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0 ||
-           what == ICSK_TIME_EARLY_RETRANS || what ==  ICSK_TIME_LOSS_PROBE) {
+           what == ICSK_TIME_EARLY_RETRANS || what == ICSK_TIME_LOSS_PROBE ||
+           what == ICSK_TIME_REO_TIMEOUT) {
                icsk->icsk_pending = what;
                icsk->icsk_timeout = jiffies + when;
                sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout);
 
 #define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
                                                         * for local resources.
                                                         */
+#define TCP_REO_TIMEOUT_MIN    (2000) /* Min RACK reordering timeout in usec */
 
 #define TCP_KEEPALIVE_TIME     (120*60*HZ)     /* two hours */
 #define TCP_KEEPALIVE_PROBES   9               /* Max of 9 keepalive probes    */
 int tcp_child_process(struct sock *parent, struct sock *child,
                      struct sk_buff *skb);
 void tcp_enter_loss(struct sock *sk);
+void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int flag);
 void tcp_clear_retrans(struct tcp_sock *tp);
 void tcp_update_metrics(struct sock *sk);
 void tcp_init_metrics(struct sock *sk);
 void tcp_retransmit_timer(struct sock *sk);
 void tcp_xmit_retransmit_queue(struct sock *);
 void tcp_simple_retransmit(struct sock *);
+void tcp_enter_recovery(struct sock *sk, bool ece_ack);
 int tcp_trim_head(struct sock *, struct sk_buff *, u32);
 int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int, gfp_t);
 
 extern void tcp_rack_advance(struct tcp_sock *tp, u8 sacked,
                             const struct skb_mstamp *xmit_time,
                             const struct skb_mstamp *ack_time);
+extern void tcp_rack_reo_timeout(struct sock *sk);
 
 /*
  * Save and compile IPv4 options, return a pointer to it
 
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
            icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+           icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||
            icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                r->idiag_timer = 1;
                r->idiag_retrans = icsk->icsk_retransmits;
 
        tcp_ecn_queue_cwr(tp);
 }
 
-static void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked,
-                              int flag)
+void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int flag)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int sndcnt = 0;
 }
 EXPORT_SYMBOL(tcp_simple_retransmit);
 
-static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
+void tcp_enter_recovery(struct sock *sk, bool ece_ack)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int mib_idx;
                u32 rto = inet_csk(sk)->icsk_rto;
                /* Offset the time elapsed after installing regular RTO */
                if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+                   icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||
                    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                        struct sk_buff *skb = tcp_write_queue_head(sk);
                        const u32 rto_time_stamp =
 
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
            icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+           icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||
            icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                timer_active    = 1;
                timer_expires   = icsk->icsk_timeout;
 
                if (tcp_in_cwnd_reduction(sk))
                        tp->prr_out += tcp_skb_pcount(skb);
 
-               if (skb == tcp_write_queue_head(sk))
+               if (skb == tcp_write_queue_head(sk) &&
+                   icsk->icsk_pending != ICSK_TIME_REO_TIMEOUT)
                        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                                                  inet_csk(sk)->icsk_rto,
                                                  TCP_RTO_MAX);
 
  * The current version is only used after recovery starts but can be
  * easily extended to detect the first loss.
  */
-static void tcp_rack_detect_loss(struct sock *sk, const struct skb_mstamp *now)
+static void tcp_rack_detect_loss(struct sock *sk, const struct skb_mstamp *now,
+                                u32 *reo_timeout)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
        u32 reo_wnd;
 
+       *reo_timeout = 0;
        /* To be more reordering resilient, allow min_rtt/4 settling delay
         * (lower-bounded to 1000uS). We use min_rtt instead of the smoothed
         * RTT because reordering is often a path property and less related
         * to queuing or delayed ACKs.
-        *
-        * TODO: measure and adapt to the observed reordering delay, and
-        * use a timer to retransmit like the delayed early retransmit.
         */
        reo_wnd = 1000;
        if (tp->rack.reord && tcp_min_rtt(tp) != ~0U)
                         * A packet is lost if its elapsed time is beyond
                         * the recent RTT plus the reordering window.
                         */
-                       if (skb_mstamp_us_delta(now, &skb->skb_mstamp) >
-                           tp->rack.rtt_us + reo_wnd) {
+                       u32 elapsed = skb_mstamp_us_delta(now,
+                                                         &skb->skb_mstamp);
+                       s32 remaining = tp->rack.rtt_us + reo_wnd - elapsed;
+
+                       if (remaining < 0) {
                                tcp_rack_mark_skb_lost(sk, skb);
+                               continue;
                        }
+
+                       /* Skip ones marked lost but not yet retransmitted */
+                       if ((scb->sacked & TCPCB_LOST) &&
+                           !(scb->sacked & TCPCB_SACKED_RETRANS))
+                               continue;
+
+                       /* Record maximum wait time (+1 to avoid 0) */
+                       *reo_timeout = max_t(u32, *reo_timeout, 1 + remaining);
+
                } else if (!(scb->sacked & TCPCB_RETRANS)) {
                        /* Original data are sent sequentially so stop early
                         * b/c the rest are all sent after rack_sent
 void tcp_rack_mark_lost(struct sock *sk, const struct skb_mstamp *now)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       u32 timeout;
 
        if (inet_csk(sk)->icsk_ca_state < TCP_CA_Recovery || !tp->rack.advanced)
                return;
+
        /* Reset the advanced flag to avoid unnecessary queue scanning */
        tp->rack.advanced = 0;
-       tcp_rack_detect_loss(sk, now);
+       tcp_rack_detect_loss(sk, now, &timeout);
+       if (timeout) {
+               timeout = usecs_to_jiffies(timeout + TCP_REO_TIMEOUT_MIN);
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_REO_TIMEOUT,
+                                         timeout, inet_csk(sk)->icsk_rto);
+       }
 }
 
 /* Record the most recently (re)sent time among the (s)acked packets
        tp->rack.mstamp = *xmit_time;
        tp->rack.advanced = 1;
 }
+
+/* We have waited long enough to accommodate reordering. Mark the expired
+ * packets lost and retransmit them.
+ */
+void tcp_rack_reo_timeout(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct skb_mstamp now;
+       u32 timeout, prior_inflight;
+
+       skb_mstamp_get(&now);
+       prior_inflight = tcp_packets_in_flight(tp);
+       tcp_rack_detect_loss(sk, &now, &timeout);
+       if (prior_inflight != tcp_packets_in_flight(tp)) {
+               if (inet_csk(sk)->icsk_ca_state != TCP_CA_Recovery) {
+                       tcp_enter_recovery(sk, false);
+                       if (!inet_csk(sk)->icsk_ca_ops->cong_control)
+                               tcp_cwnd_reduction(sk, 1, 0);
+               }
+               tcp_xmit_retransmit_queue(sk);
+       }
+       if (inet_csk(sk)->icsk_pending != ICSK_TIME_RETRANS)
+               tcp_rearm_rto(sk);
+}
 
        event = icsk->icsk_pending;
 
        switch (event) {
+       case ICSK_TIME_REO_TIMEOUT:
+               tcp_rack_reo_timeout(sk);
+               break;
        case ICSK_TIME_EARLY_RETRANS:
                tcp_resume_early_retransmit(sk);
                break;
 
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
            icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+           icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||
            icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                timer_active    = 1;
                timer_expires   = icsk->icsk_timeout;