return cur_ack;
 }
 
-static void update_una(struct mptcp_sock *msk,
-                      struct mptcp_options_received *mp_opt)
+static void ack_update_msk(struct mptcp_sock *msk,
+                          const struct sock *ssk,
+                          struct mptcp_options_received *mp_opt)
 {
        u64 new_snd_una, snd_una, old_snd_una = atomic64_read(&msk->snd_una);
+       u64 new_wnd_end, wnd_end, old_wnd_end = atomic64_read(&msk->wnd_end);
        u64 snd_nxt = READ_ONCE(msk->snd_nxt);
+       struct sock *sk = (struct sock *)msk;
 
        /* avoid ack expansion on update conflict, to reduce the risk of
         * wrongly expanding to a future ack sequence number, which is way
        if (after64(new_snd_una, snd_nxt))
                new_snd_una = old_snd_una;
 
+       new_wnd_end = new_snd_una + tcp_sk(ssk)->snd_wnd;
+
+       while (after64(new_wnd_end, old_wnd_end)) {
+               wnd_end = old_wnd_end;
+               old_wnd_end = atomic64_cmpxchg(&msk->wnd_end, wnd_end,
+                                              new_wnd_end);
+               if (old_wnd_end == wnd_end) {
+                       if (mptcp_send_head(sk))
+                               mptcp_schedule_work(sk);
+                       break;
+               }
+       }
+
        while (after64(new_snd_una, old_snd_una)) {
                snd_una = old_snd_una;
                old_snd_una = atomic64_cmpxchg(&msk->snd_una, snd_una,
                                               new_snd_una);
                if (old_snd_una == snd_una) {
-                       mptcp_data_acked((struct sock *)msk);
+                       mptcp_data_acked(sk);
                        break;
                }
        }
         * monodirectional flows will stuck
         */
        if (mp_opt.use_ack)
-               update_una(msk, &mp_opt);
+               ack_update_msk(msk, sk, &mp_opt);
 
        /* Zero-data-length packets are dropped by the caller and not
         * propagated to the MPTCP layer, so the skb extension does not
 
        return msk->subflow;
 }
 
+/* Returns end sequence number of the receiver's advertised window */
+static u64 mptcp_wnd_end(const struct mptcp_sock *msk)
+{
+       return atomic64_read(&msk->wnd_end);
+}
+
 static bool mptcp_is_tcpsk(struct sock *sk)
 {
        struct socket *sock = sk->sk_socket;
        if (after64(seq, max_seq)) {
                /* out of window */
                mptcp_drop(sk, skb);
+               pr_debug("oow by %ld", (unsigned long)seq - (unsigned long)max_seq);
                MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_NODSSWINDOW);
                return;
        }
         */
        if (__mptcp_check_fallback(msk))
                atomic64_set(&msk->snd_una, msk->snd_nxt);
+
        snd_una = atomic64_read(&msk->snd_una);
 
        list_for_each_entry_safe(dfrag, dtmp, &msk->rtx_queue, list) {
        unsigned int flags;
 };
 
+static int mptcp_check_allowed_size(struct mptcp_sock *msk, u64 data_seq,
+                                   int avail_size)
+{
+       u64 window_end = mptcp_wnd_end(msk);
+
+       if (__mptcp_check_fallback(msk))
+               return avail_size;
+
+       if (!before64(data_seq + avail_size, window_end)) {
+               u64 allowed_size = window_end - data_seq;
+
+               return min_t(unsigned int, allowed_size, avail_size);
+       }
+
+       return avail_size;
+}
+
 static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
                              struct mptcp_data_frag *dfrag,
                              struct mptcp_sendmsg_info *info)
 {
        u64 data_seq = dfrag->data_seq + info->sent;
        struct mptcp_sock *msk = mptcp_sk(sk);
+       bool zero_window_probe = false;
        struct mptcp_ext *mpext = NULL;
        struct sk_buff *skb, *tail;
        bool can_collapse = false;
                        avail_size = info->size_goal - skb->len;
        }
 
+       /* Zero window and all data acked? Probe. */
+       avail_size = mptcp_check_allowed_size(msk, data_seq, avail_size);
+       if (avail_size == 0) {
+               if (skb || atomic64_read(&msk->snd_una) != msk->snd_nxt)
+                       return 0;
+               zero_window_probe = true;
+               data_seq = atomic64_read(&msk->snd_una) - 1;
+               avail_size = 1;
+       }
+
        if (WARN_ON_ONCE(info->sent > info->limit ||
                         info->limit > dfrag->data_len))
                return 0;
        if (skb == tail) {
                WARN_ON_ONCE(!can_collapse);
                mpext->data_len += ret;
+               WARN_ON_ONCE(zero_window_probe);
                goto out;
        }
 
                 mpext->data_seq, mpext->subflow_seq, mpext->data_len,
                 mpext->dsn64);
 
+       if (zero_window_probe) {
+               mptcp_subflow_ctx(ssk)->rel_write_seq += ret;
+               mpext->frozen = 1;
+               ret = 0;
+               tcp_push_pending_frames(ssk);
+       }
 out:
        mptcp_subflow_ctx(ssk)->rel_write_seq += ret;
        return ret;
        info.limit = dfrag->already_sent;
        while (info.sent < dfrag->already_sent) {
                ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
-               if (ret < 0)
+               if (ret <= 0)
                        break;
 
                MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RETRANSSEGS);
        msk->write_seq = subflow_req->idsn + 1;
        msk->snd_nxt = msk->write_seq;
        atomic64_set(&msk->snd_una, msk->write_seq);
+       atomic64_set(&msk->wnd_end, msk->snd_nxt + req->rsk_rcv_wnd);
+
        if (mp_opt->mp_capable) {
                msk->can_ack = true;
                msk->remote_key = mp_opt->sndr_key;
                                      TCP_INIT_CWND * tp->advmss);
        if (msk->rcvq_space.space == 0)
                msk->rcvq_space.space = TCP_INIT_CWND * TCP_MSS_DEFAULT;
+
+       atomic64_set(&msk->wnd_end, msk->snd_nxt + tcp_sk(ssk)->snd_wnd);
 }
 
 static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,