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

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
...@@ -112,9 +112,14 @@ static int __subflow_init_req(struct request_sock *req, const struct sock *sk_li ...@@ -112,9 +112,14 @@ static int __subflow_init_req(struct request_sock *req, const struct sock *sk_li
return 0; return 0;
} }
static void subflow_init_req(struct request_sock *req, /* Init mptcp request socket.
const struct sock *sk_listener, *
struct sk_buff *skb) * 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)
{ {
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener); struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
...@@ -125,7 +130,7 @@ static void subflow_init_req(struct request_sock *req, ...@@ -125,7 +130,7 @@ static void subflow_init_req(struct request_sock *req,
ret = __subflow_init_req(req, sk_listener); ret = __subflow_init_req(req, sk_listener);
if (ret) if (ret)
return; return 0;
mptcp_get_options(skb, &mp_opt); mptcp_get_options(skb, &mp_opt);
...@@ -133,7 +138,7 @@ static void subflow_init_req(struct request_sock *req, ...@@ -133,7 +138,7 @@ static void subflow_init_req(struct request_sock *req,
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE); SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE);
if (mp_opt.mp_join) if (mp_opt.mp_join)
return; return 0;
} else if (mp_opt.mp_join) { } else if (mp_opt.mp_join) {
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX); SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX);
} }
...@@ -157,7 +162,7 @@ static void subflow_init_req(struct request_sock *req, ...@@ -157,7 +162,7 @@ static void subflow_init_req(struct request_sock *req,
} else { } else {
subflow_req->mp_capable = 1; subflow_req->mp_capable = 1;
} }
return; return 0;
} }
err = mptcp_token_new_request(req); err = mptcp_token_new_request(req);
...@@ -175,7 +180,11 @@ static void subflow_init_req(struct request_sock *req, ...@@ -175,7 +180,11 @@ static void subflow_init_req(struct request_sock *req,
subflow_req->remote_nonce = mp_opt.nonce; subflow_req->remote_nonce = mp_opt.nonce;
subflow_req->msk = subflow_token_join_request(req, skb); 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)) if (mptcp_can_accept_new_subflow(subflow_req->msk))
subflow_init_req_cookie_join_save(subflow_req, skb); subflow_init_req_cookie_join_save(subflow_req, skb);
} }
...@@ -183,6 +192,8 @@ static void subflow_init_req(struct request_sock *req, ...@@ -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, pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
subflow_req->remote_nonce, subflow_req->msk); subflow_req->remote_nonce, subflow_req->msk);
} }
return 0;
} }
int mptcp_subflow_init_cookie_req(struct request_sock *req, 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, ...@@ -234,6 +245,7 @@ static struct dst_entry *subflow_v4_route_req(const struct sock *sk,
struct request_sock *req) struct request_sock *req)
{ {
struct dst_entry *dst; struct dst_entry *dst;
int err;
tcp_rsk(req)->is_mptcp = 1; tcp_rsk(req)->is_mptcp = 1;
...@@ -241,8 +253,14 @@ static struct dst_entry *subflow_v4_route_req(const struct sock *sk, ...@@ -241,8 +253,14 @@ static struct dst_entry *subflow_v4_route_req(const struct sock *sk,
if (!dst) if (!dst)
return NULL; return NULL;
subflow_init_req(req, sk, skb); err = subflow_init_req(req, sk, skb);
return dst; 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) #if IS_ENABLED(CONFIG_MPTCP_IPV6)
...@@ -252,6 +270,7 @@ static struct dst_entry *subflow_v6_route_req(const struct sock *sk, ...@@ -252,6 +270,7 @@ static struct dst_entry *subflow_v6_route_req(const struct sock *sk,
struct request_sock *req) struct request_sock *req)
{ {
struct dst_entry *dst; struct dst_entry *dst;
int err;
tcp_rsk(req)->is_mptcp = 1; tcp_rsk(req)->is_mptcp = 1;
...@@ -259,8 +278,14 @@ static struct dst_entry *subflow_v6_route_req(const struct sock *sk, ...@@ -259,8 +278,14 @@ static struct dst_entry *subflow_v6_route_req(const struct sock *sk,
if (!dst) if (!dst)
return NULL; return NULL;
subflow_init_req(req, sk, skb); err = subflow_init_req(req, sk, skb);
return dst; if (err == 0)
return dst;
dst_release(dst);
if (!req->syncookie)
tcp6_request_sock_ops.send_reset(sk, skb);
return NULL;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment