Commit 55b47ca7 authored by Paolo Abeni's avatar Paolo Abeni Committed by Jakub Kicinski
Browse files

mptcp: fix active subflow finalization



Active subflow are inserted into the connection list at creation time.
When the MPJ handshake completes successfully, a new subflow creation
netlink event is generated correctly, but the current code wrongly
avoid initializing a couple of subflow data.

The above will cause misbehavior on a few exceptional events: unneeded
mptcp-level retransmission on msk-level sequence wrap-around and infinite
mapping fallback even when a MPJ socket is present.

Address the issue factoring out the needed initialization in a new helper
and invoking the latter from __mptcp_finish_join() time for passive
subflow and from mptcp_finish_join() for active ones.

Fixes: 0530020a ("mptcp: track and update contiguous data status")
Cc: stable@vger.kernel.org
Reviewed-by: default avatarMat Martineau <martineau@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarMat Martineau <martineau@kernel.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6b9831bf
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -825,6 +825,13 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
	mptcp_data_unlock(sk);
}

static void mptcp_subflow_joined(struct mptcp_sock *msk, struct sock *ssk)
{
	mptcp_subflow_ctx(ssk)->map_seq = READ_ONCE(msk->ack_seq);
	WRITE_ONCE(msk->allow_infinite_fallback, false);
	mptcp_event(MPTCP_EVENT_SUB_ESTABLISHED, msk, ssk, GFP_ATOMIC);
}

static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
{
	struct sock *sk = (struct sock *)msk;
@@ -839,6 +846,7 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
		mptcp_sock_graft(ssk, sk->sk_socket);

	mptcp_sockopt_sync_locked(msk, ssk);
	mptcp_subflow_joined(msk, ssk);
	return true;
}

@@ -3485,14 +3493,16 @@ bool mptcp_finish_join(struct sock *ssk)
		return false;
	}

	if (!list_empty(&subflow->node))
		goto out;
	/* active subflow, already present inside the conn_list */
	if (!list_empty(&subflow->node)) {
		mptcp_subflow_joined(msk, ssk);
		return true;
	}

	if (!mptcp_pm_allow_new_subflow(msk))
		goto err_prohibited;

	/* active connections are already on conn_list.
	 * If we can't acquire msk socket lock here, let the release callback
	/* If we can't acquire msk socket lock here, let the release callback
	 * handle it
	 */
	mptcp_data_lock(parent);
@@ -3515,11 +3525,6 @@ bool mptcp_finish_join(struct sock *ssk)
		return false;
	}

	subflow->map_seq = READ_ONCE(msk->ack_seq);
	WRITE_ONCE(msk->allow_infinite_fallback, false);

out:
	mptcp_event(MPTCP_EVENT_SUB_ESTABLISHED, msk, ssk, GFP_ATOMIC);
	return true;
}