Commit 3ecfbe3e authored by Florian Westphal's avatar Florian Westphal Committed by Jakub Kicinski
Browse files

mptcp: emit tcp reset when a join request fails



RFC 8684 says:
 If the token is unknown or the host wants to refuse subflow establishment
 (for example, due to a limit on the number of subflows it will permit),
 the receiver will send back a reset (RST) signal, analogous to an unknown
 port in TCP, containing an MP_TCPRST option (Section 3.6) with an
 "MPTCP specific error" reason code.

mptcp-next doesn't support MP_TCPRST yet, this can be added in another
change.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Reviewed-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7ea851d1
Loading
Loading
Loading
Loading
+36 −11
Original line number Diff line number Diff line
@@ -112,7 +112,12 @@ static int __subflow_init_req(struct request_sock *req, const struct sock *sk_li
	return 0;
}

static void subflow_init_req(struct request_sock *req,
/* Init mptcp request socket.
 *
 * Returns an error code if a JOIN has failed and a TCP reset
 * should be sent.
 */
static int subflow_init_req(struct request_sock *req,
			    const struct sock *sk_listener,
			    struct sk_buff *skb)
{
@@ -125,7 +130,7 @@ static void subflow_init_req(struct request_sock *req,

	ret = __subflow_init_req(req, sk_listener);
	if (ret)
		return;
		return 0;

	mptcp_get_options(skb, &mp_opt);

@@ -133,7 +138,7 @@ static void subflow_init_req(struct request_sock *req,
		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE);

		if (mp_opt.mp_join)
			return;
			return 0;
	} else if (mp_opt.mp_join) {
		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX);
	}
@@ -157,7 +162,7 @@ static void subflow_init_req(struct request_sock *req,
			} else {
				subflow_req->mp_capable = 1;
			}
			return;
			return 0;
		}

		err = mptcp_token_new_request(req);
@@ -175,7 +180,11 @@ static void subflow_init_req(struct request_sock *req,
		subflow_req->remote_nonce = mp_opt.nonce;
		subflow_req->msk = subflow_token_join_request(req, skb);

		if (unlikely(req->syncookie) && subflow_req->msk) {
		/* Can't fall back to TCP in this case. */
		if (!subflow_req->msk)
			return -EPERM;

		if (unlikely(req->syncookie)) {
			if (mptcp_can_accept_new_subflow(subflow_req->msk))
				subflow_init_req_cookie_join_save(subflow_req, skb);
		}
@@ -183,6 +192,8 @@ static void subflow_init_req(struct request_sock *req,
		pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
			 subflow_req->remote_nonce, subflow_req->msk);
	}

	return 0;
}

int mptcp_subflow_init_cookie_req(struct request_sock *req,
@@ -234,6 +245,7 @@ static struct dst_entry *subflow_v4_route_req(const struct sock *sk,
					      struct request_sock *req)
{
	struct dst_entry *dst;
	int err;

	tcp_rsk(req)->is_mptcp = 1;

@@ -241,8 +253,14 @@ static struct dst_entry *subflow_v4_route_req(const struct sock *sk,
	if (!dst)
		return NULL;

	subflow_init_req(req, sk, skb);
	err = subflow_init_req(req, sk, skb);
	if (err == 0)
		return dst;

	dst_release(dst);
	if (!req->syncookie)
		tcp_request_sock_ops.send_reset(sk, skb);
	return NULL;
}

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
@@ -252,6 +270,7 @@ static struct dst_entry *subflow_v6_route_req(const struct sock *sk,
					      struct request_sock *req)
{
	struct dst_entry *dst;
	int err;

	tcp_rsk(req)->is_mptcp = 1;

@@ -259,8 +278,14 @@ static struct dst_entry *subflow_v6_route_req(const struct sock *sk,
	if (!dst)
		return NULL;

	subflow_init_req(req, sk, skb);
	err = subflow_init_req(req, sk, skb);
	if (err == 0)
		return dst;

	dst_release(dst);
	if (!req->syncookie)
		tcp6_request_sock_ops.send_reset(sk, skb);
	return NULL;
}
#endif