Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / net / mptcp / protocol.c
index 8bf2199..29a2d69 100644 (file)
@@ -392,6 +392,14 @@ static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq)
        return false;
 }
 
+static void mptcp_set_datafin_timeout(const struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       mptcp_sk(sk)->timer_ival = min(TCP_RTO_MAX,
+                                      TCP_RTO_MIN << icsk->icsk_retransmits);
+}
+
 static void mptcp_set_timeout(const struct sock *sk, const struct sock *ssk)
 {
        long tout = ssk && inet_csk(ssk)->icsk_pending ?
@@ -1062,7 +1070,7 @@ out:
        }
 
        if (snd_una == READ_ONCE(msk->snd_nxt)) {
-               if (msk->timer_ival)
+               if (msk->timer_ival && !mptcp_data_fin_enabled(msk))
                        mptcp_stop_timer(sk);
        } else {
                mptcp_reset_timer(sk);
@@ -2287,8 +2295,19 @@ static void __mptcp_retrans(struct sock *sk)
 
        __mptcp_clean_una_wakeup(sk);
        dfrag = mptcp_rtx_head(sk);
-       if (!dfrag)
+       if (!dfrag) {
+               if (mptcp_data_fin_enabled(msk)) {
+                       struct inet_connection_sock *icsk = inet_csk(sk);
+
+                       icsk->icsk_retransmits++;
+                       mptcp_set_datafin_timeout(sk);
+                       mptcp_send_ack(msk);
+
+                       goto reset_timer;
+               }
+
                return;
+       }
 
        ssk = mptcp_subflow_get_retrans(msk);
        if (!ssk)
@@ -2474,6 +2493,8 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
                        pr_debug("Sending DATA_FIN on subflow %p", ssk);
                        mptcp_set_timeout(sk, ssk);
                        tcp_send_ack(ssk);
+                       if (!mptcp_timer_pending(sk))
+                               mptcp_reset_timer(sk);
                }
                break;
        }