extern bool tcp_remember_stamp(struct sock *sk);
 extern bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw);
 extern void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
-                                  struct tcp_fastopen_cookie *cookie);
+                                  struct tcp_fastopen_cookie *cookie,
+                                  int *syn_loss, unsigned long *last_syn_loss);
 extern void tcp_fastopen_cache_set(struct sock *sk, u16 mss,
-                                  struct tcp_fastopen_cookie *cookie);
+                                  struct tcp_fastopen_cookie *cookie,
+                                  bool syn_lost);
 extern void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst);
 extern void tcp_disable_fack(struct tcp_sock *tp);
 extern void tcp_close(struct sock *sk, long timeout);
 
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *data = tcp_write_queue_head(sk);
        u16 mss = tp->rx_opt.mss_clamp;
+       bool syn_drop;
 
        if (mss == tp->rx_opt.user_mss) {
                struct tcp_options_received opt;
                mss = opt.mss_clamp;
        }
 
-       tcp_fastopen_cache_set(sk, mss, cookie);
+       /* The SYN-ACK neither has cookie nor acknowledges the data. Presumably
+        * the remote receives only the retransmitted (regular) SYNs: either
+        * the original SYN-data or the corresponding SYN-ACK is lost.
+        */
+       syn_drop = (cookie->len <= 0 && data &&
+                   inet_csk(sk)->icsk_retransmits);
+
+       tcp_fastopen_cache_set(sk, mss, cookie, syn_drop);
 
        if (data) { /* Retransmit unacked data in SYN */
                tcp_retransmit_skb(sk, data);
 
 
 struct tcp_fastopen_metrics {
        u16     mss;
+       u16     syn_loss:10;            /* Recurring Fast Open SYN losses */
+       unsigned long   last_syn_loss;  /* Last Fast Open SYN loss */
        struct  tcp_fastopen_cookie     cookie;
 };
 
        tm->tcpm_ts = 0;
        tm->tcpm_ts_stamp = 0;
        tm->tcpm_fastopen.mss = 0;
+       tm->tcpm_fastopen.syn_loss = 0;
        tm->tcpm_fastopen.cookie.len = 0;
 }
 
 static DEFINE_SEQLOCK(fastopen_seqlock);
 
 void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
-                           struct tcp_fastopen_cookie *cookie)
+                           struct tcp_fastopen_cookie *cookie,
+                           int *syn_loss, unsigned long *last_syn_loss)
 {
        struct tcp_metrics_block *tm;
 
                        if (tfom->mss)
                                *mss = tfom->mss;
                        *cookie = tfom->cookie;
+                       *syn_loss = tfom->syn_loss;
+                       *last_syn_loss = *syn_loss ? tfom->last_syn_loss : 0;
                } while (read_seqretry(&fastopen_seqlock, seq));
        }
        rcu_read_unlock();
 }
 
-
 void tcp_fastopen_cache_set(struct sock *sk, u16 mss,
-                           struct tcp_fastopen_cookie *cookie)
+                           struct tcp_fastopen_cookie *cookie, bool syn_lost)
 {
        struct tcp_metrics_block *tm;
 
                tfom->mss = mss;
                if (cookie->len > 0)
                        tfom->cookie = *cookie;
+               if (syn_lost) {
+                       ++tfom->syn_loss;
+                       tfom->last_syn_loss = jiffies;
+               } else
+                       tfom->syn_loss = 0;
                write_sequnlock_bh(&fastopen_seqlock);
        }
        rcu_read_unlock();
 
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_fastopen_request *fo = tp->fastopen_req;
-       int space, i, err = 0, iovlen = fo->data->msg_iovlen;
+       int syn_loss = 0, space, i, err = 0, iovlen = fo->data->msg_iovlen;
        struct sk_buff *syn_data = NULL, *data;
+       unsigned long last_syn_loss = 0;
+
+       tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie,
+                              &syn_loss, &last_syn_loss);
+       /* Recurring FO SYN losses: revert to regular handshake temporarily */
+       if (syn_loss > 1 &&
+           time_before(jiffies, last_syn_loss + (60*HZ << syn_loss))) {
+               fo->cookie.len = -1;
+               goto fallback;
+       }
 
-       tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie);
        if (fo->cookie.len <= 0)
                goto fallback;