MPTCP currently generate a dummy data_fin for fallback socket
when the fallback subflow has completed data reception using
the current ack_seq.
We are going to introduce backlog usage for the msk soon, even
for fallback sockets: the above condition will be not be correct
as it will ignore data_seq sitting in the backlog.
Instead generate the dummy data_fin when the last data packet is
extracted by the fallback subflow.
The scenario with fallback socket receiving a reset while the
receive queue empty is catched via the generic 'all subflows closed'
timeout: ensure such timeout is zero for fallback sockets.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
net/mptcp/ctrl.c | 2 ++
net/mptcp/subflow.c | 16 ++++++++--------
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c
index fed40dae5583a..4f7795968abe2 100644
--- a/net/mptcp/ctrl.c
+++ b/net/mptcp/ctrl.c
@@ -74,6 +74,8 @@ unsigned int mptcp_stale_loss_cnt(const struct net *net)
unsigned int mptcp_close_timeout(const struct sock *sk)
{
+ if (__mptcp_check_fallback(mptcp_sk(sk)))
+ return 0;
if (sock_flag(sk, SOCK_DEAD))
return TCP_TIMEWAIT_LEN;
return mptcp_get_pernet(sock_net(sk))->close_timeout;
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index c8a7e4b59db11..5339a00528a7a 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1293,14 +1293,6 @@ static void subflow_sched_work_if_closed(struct mptcp_sock *msk, struct sock *ss
if (!test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
mptcp_schedule_work(sk);
-
- /* when the fallback subflow closes the rx side, trigger a 'dummy'
- * ingress data fin, so that the msk state will follow along
- */
- if (__mptcp_check_fallback(msk) && subflow_is_done(ssk) &&
- msk->first == ssk &&
- mptcp_update_rcv_data_fin(msk, READ_ONCE(msk->ack_seq), true))
- mptcp_schedule_work(sk);
}
static bool mptcp_subflow_fail(struct mptcp_sock *msk, struct sock *ssk)
@@ -1433,6 +1425,14 @@ static bool subflow_check_data_avail(struct sock *ssk)
subflow->map_data_len = skb->len;
subflow->map_subflow_seq = tcp_sk(ssk)->copied_seq - subflow->ssn_offset;
WRITE_ONCE(subflow->data_avail, true);
+
+ /* last skb in closed fallback subflow: we are at data fin */
+ if (subflow_is_done(ssk) && ssk == msk->first &&
+ skb == skb_peek_tail(&ssk->sk_receive_queue)) {
+ mptcp_update_rcv_data_fin(msk, subflow->map_seq +
+ subflow->map_data_len, true);
+ subflow->map_data_fin = 1;
+ }
return true;
}
--
2.51.0