From patchwork Thu Nov 5 17:01:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1395128 X-Patchwork-Delegate: fw@strlen.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=198.145.21.10; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CRqYg3yvjz9sSn for ; Fri, 6 Nov 2020 04:01:42 +1100 (AEDT) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 1A46516646E2E; Thu, 5 Nov 2020 09:01:40 -0800 (PST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id AF09216646E28 for ; Thu, 5 Nov 2020 09:01:38 -0800 (PST) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kaidl-0007Cp-4x; Thu, 05 Nov 2020 18:01:37 +0100 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 5 Nov 2020 18:01:22 +0100 Message-Id: <20201105170126.5627-2-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201105170126.5627-1-fw@strlen.de> References: <20201105170126.5627-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: NO22I2QICE4TKIFNTPULEVGZ6I4IUN7U X-Message-ID-Hash: NO22I2QICE4TKIFNTPULEVGZ6I4IUN7U X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [PATCH MPTCP 1/5] tcp: make two mptcp helpers available to tcp stack List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: needed by followup patches to add mptcp reset (and fastclose) options to tcp reset packets. Signed-off-by: Florian Westphal --- include/net/mptcp.h | 10 ++++++++++ include/net/tcp.h | 5 +++++ net/mptcp/protocol.h | 11 ----------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index b6cf07143a8a..3d57607982fa 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -78,6 +78,11 @@ static inline bool rsk_drop_req(const struct request_sock *req) return tcp_rsk(req)->is_mptcp && tcp_rsk(req)->drop_req; } +static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) +{ + return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP); +} + void mptcp_space(const struct sock *ssk, int *space, int *full_space); bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb, unsigned int *size, struct mptcp_out_options *opts); @@ -169,6 +174,11 @@ static inline bool rsk_drop_req(const struct request_sock *req) return false; } +static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) +{ + return NULL; +} + static inline void mptcp_parse_option(const struct sk_buff *skb, const unsigned char *ptr, int opsize, struct tcp_options_received *opt_rx) diff --git a/include/net/tcp.h b/include/net/tcp.h index f3d42cb626fc..8115164e0df6 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2377,4 +2377,9 @@ static inline u64 tcp_transmit_time(const struct sock *sk) return 0; } +static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) +{ + return htonl((TCPOPT_MPTCP << 24) | (len << 16) | (subopt << 12) | + ((nib & 0xF) << 8) | field); +} #endif /* _TCP_H */ diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index d29c6a4749eb..66bd4d096753 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -139,12 +139,6 @@ struct mptcp_options_received { u16 port; }; -static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) -{ - return htonl((TCPOPT_MPTCP << 24) | (len << 16) | (subopt << 12) | - ((nib & 0xF) << 8) | field); -} - struct mptcp_addr_info { sa_family_t family; __be16 port; @@ -568,11 +562,6 @@ void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk); void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, u8 rm_id); int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); -static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) -{ - return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP); -} - void mptcp_diag_subflow_init(struct tcp_ulp_ops *ops); static inline bool __mptcp_check_fallback(const struct mptcp_sock *msk) From patchwork Thu Nov 5 17:01:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1395130 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=198.145.21.10; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CRqYk51lVz9sRK for ; Fri, 6 Nov 2020 04:01:46 +1100 (AEDT) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 2E66116646E2F; Thu, 5 Nov 2020 09:01:45 -0800 (PST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 1275616646E26 for ; Thu, 5 Nov 2020 09:01:43 -0800 (PST) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kaidp-0007Cx-CA; Thu, 05 Nov 2020 18:01:41 +0100 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 5 Nov 2020 18:01:23 +0100 Message-Id: <20201105170126.5627-3-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201105170126.5627-1-fw@strlen.de> References: <20201105170126.5627-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: 472WUBSCQNLGNU6EQMAW7KXYEZEKRXXP X-Message-ID-Hash: 472WUBSCQNLGNU6EQMAW7KXYEZEKRXXP X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [PATCH MPTCP 2/5] tcp: parse mptcp options contained in reset packets List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: In MPTCP, TCP-level resets only affect the subflow, not the logical MPTCP connection. MPTCP supports a reset-specific TCP option to enable senders to tell the receiver why the subflow was reset, for instance due to a protocol error, because the subflow is deemed too slow, a middlebox interfering with mptcp options was detected and so on. This allows an MPTCP receiver to make a decision to reopen the subflow at a later time or even completely disable the path. For this to work its needed to call the mptcp option decode function when a tcp reset is received. For this to be useful the reason code has to be propagated to the Path Manager to use it to e.g. reconnect at a later time. Signed-off-by: Florian Westphal --- include/net/tcp.h | 2 +- net/ipv4/tcp_input.c | 13 ++++++++----- net/ipv4/tcp_minisocks.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 8115164e0df6..c0fef9e9ba20 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -610,7 +610,7 @@ void tcp_skb_collapse_tstamp(struct sk_buff *skb, /* tcp_input.c */ void tcp_rearm_rto(struct sock *sk); void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); -void tcp_reset(struct sock *sk); +void tcp_reset(struct sock *sk, struct sk_buff *skb); void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); void tcp_fin(struct sock *sk); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fb3a7750f623..fb65d3519439 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4217,10 +4217,13 @@ static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq) } /* When we get a reset we do this. */ -void tcp_reset(struct sock *sk) +void tcp_reset(struct sock *sk, struct sk_buff *skb) { trace_tcp_receive_reset(sk); + if (sk_is_mptcp(sk)) + mptcp_incoming_options(sk, skb); + /* We want the right error as BSD sees it (and indeed as we do). */ switch (sk->sk_state) { case TCP_SYN_SENT: @@ -5603,7 +5606,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, &tp->last_oow_ack_time)) tcp_send_dupack(sk, skb); } else if (tcp_reset_check(sk, skb)) { - tcp_reset(sk); + tcp_reset(sk, skb); } goto discard; } @@ -5639,7 +5642,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, } if (rst_seq_match) - tcp_reset(sk); + tcp_reset(sk, skb); else { /* Disable TFO if RST is out-of-order * and no data has been received @@ -6076,7 +6079,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, */ if (th->rst) { - tcp_reset(sk); + tcp_reset(sk, skb); goto discard; } @@ -6518,7 +6521,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - tcp_reset(sk); + tcp_reset(sk, skb); return 1; } } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 495dda2449fe..0055ae0a3bf8 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -801,7 +801,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, req->rsk_ops->send_reset(sk, skb); } else if (fastopen) { /* received a valid RST pkt */ reqsk_fastopen_remove(sk, req, true); - tcp_reset(sk); + tcp_reset(sk, skb); } if (!fastopen) { inet_csk_reqsk_queue_drop(sk, req); From patchwork Thu Nov 5 17:01:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1395131 X-Patchwork-Delegate: fw@strlen.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=2001:19d0:306:5::1; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [IPv6:2001:19d0:306:5::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CRqYt3D2Zz9sSn for ; Fri, 6 Nov 2020 04:01:54 +1100 (AEDT) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 3B20016646E30; Thu, 5 Nov 2020 09:01:50 -0800 (PST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 6B81D16646E30 for ; Thu, 5 Nov 2020 09:01:47 -0800 (PST) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kaidt-0007D9-ME; Thu, 05 Nov 2020 18:01:45 +0100 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 5 Nov 2020 18:01:24 +0100 Message-Id: <20201105170126.5627-4-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201105170126.5627-1-fw@strlen.de> References: <20201105170126.5627-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: 7VKOR65WVPGQG4QLOTAN3HMWS4AD6MP5 X-Message-ID-Hash: 7VKOR65WVPGQG4QLOTAN3HMWS4AD6MP5 X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [PATCH MPTCP 3/5] mptcp: add mptcp reset option support List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: The MPTCP reset option allows to carry a mptcp-specific error code that provides more information on the nature of a connection reset. The Reset option data received gets stored in the mptcp skb extension structure so it can be consumed by e.g. path management. When a subflow is closed, the desired error code that should be sent to the peer is placed in the subflow context structure. If close happens before a suitable tcp socket has been created (for example, when HMAC fails validation), the reset code can be placed in the mptcp skb extension which then gets added to the TCP reset skb. Signed-off-by: Florian Westphal --- include/net/mptcp.h | 6 ++++-- include/net/tcp.h | 3 +++ net/ipv4/tcp_ipv4.c | 21 ++++++++++++++++++++- net/ipv6/tcp_ipv6.c | 19 +++++++++++++++++++ net/mptcp/options.c | 42 +++++++++++++++++++++++++++++++++++++----- net/mptcp/protocol.c | 12 +++++++++--- net/mptcp/protocol.h | 18 ++++++++++++++++++ net/mptcp/subflow.c | 27 ++++++++++++++++++++++++--- 8 files changed, 134 insertions(+), 14 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 3d57607982fa..0aed06330a25 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -30,8 +30,8 @@ struct mptcp_ext { ack64:1, mpc_map:1, frozen:1, - __unused:1; - /* one byte hole */ + reset_transient:1; + u8 reset_reason:4; }; struct mptcp_out_options { @@ -50,6 +50,8 @@ struct mptcp_out_options { u8 rm_id; u8 join_id; u8 backup; + u8 reset_reason:4; + u8 reset_transient:1; u32 nonce; u64 thmac; u32 token; diff --git a/include/net/tcp.h b/include/net/tcp.h index c0fef9e9ba20..899f87346b49 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -193,6 +193,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOPT_FASTOPEN_MAGIC 0xF989 #define TCPOPT_SMC_MAGIC 0xE2D4C3D9 +/* MPTCP suboptions used in TCP */ +#define MPTCPOPT_RST 8 /* * TCP option lengths */ @@ -216,6 +218,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_MD5SIG_ALIGNED 20 #define TCPOLEN_MSS_ALIGNED 4 #define TCPOLEN_EXP_SMC_BASE_ALIGNED 8 +#define TCPOLEN_MPTCP_RST 4 /* Flags in tp->nonagle */ #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 7352c097ae48..c96aea5514c6 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -660,9 +660,11 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); struct { struct tcphdr th; + __be32 opt[(TCPOLEN_MPTCP_RST >> 2) #ifdef CONFIG_TCP_MD5SIG - __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; + + (TCPOLEN_MD5SIG_ALIGNED >> 2) #endif + ]; } rep; struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG @@ -770,6 +772,23 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ip_hdr(skb)->daddr, &rep.th); } #endif + /* Can't co-exist with TCPMD5, hence check rep.opt[0] */ + if (sk && sk_fullsock(sk) && sk_is_mptcp(sk) && rep.opt[0] == 0) { + const struct mptcp_ext *ext = mptcp_get_ext(skb); + u8 flags = 0, reason = 0; + + if (ext) { + flags = ext->reset_transient; + reason = ext->reset_reason; + } + + rep.opt[0] = mptcp_option(MPTCPOPT_RST, TCPOLEN_MPTCP_RST, + flags, reason); + + arg.iov[0].iov_len += TCPOLEN_MPTCP_RST; + rep.th.doff = arg.iov[0].iov_len / 4; + } + arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, /* XXX */ arg.iov[0].iov_len, IPPROTO_TCP, 0); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8db59f4e5f13..cfe8d6b4c34c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -868,6 +868,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); + bool mptcp_reset = false; struct dst_entry *dst; __be32 *topt; __u32 mark = 0; @@ -879,6 +880,11 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 tot_len += TCPOLEN_MD5SIG_ALIGNED; #endif + if (rst && sk && sk_fullsock(sk) && sk_is_mptcp(sk) && !key) { + tot_len += TCPOLEN_MPTCP_RST; + mptcp_reset = true; + } + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); if (!buff) @@ -909,6 +915,19 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 *topt++ = htonl(tsecr); } + if (mptcp_reset) { + const struct mptcp_ext *ext = mptcp_get_ext(skb); + u8 flags = 0, reason = 0; + + if (ext) { + flags = ext->reset_transient; + reason = ext->reset_reason; + } + + *topt++ = mptcp_option(MPTCPOPT_RST, TCPOLEN_MPTCP_RST, + flags, reason); + } + #ifdef CONFIG_TCP_MD5SIG if (key) { *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 248e3930c0cb..785a9f4e7da8 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -281,7 +281,17 @@ static void mptcp_parse_option(const struct sk_buff *skb, mp_opt->rm_id = *ptr++; pr_debug("RM_ADDR: id=%d", mp_opt->rm_id); break; + case MPTCPOPT_RST: + if (opsize != TCPOLEN_MPTCP_RST) + break; + if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) + break; + mp_opt->reset = 1; + flags = *ptr++; + mp_opt->reset_transient = flags & MPTCP_RST_TRANSIENT; + mp_opt->reset_reason = *ptr; + break; default: break; } @@ -302,6 +312,7 @@ void mptcp_get_options(const struct sk_buff *skb, mp_opt->port = 0; mp_opt->rm_addr = 0; mp_opt->dss = 0; + mp_opt->reset = 0; length = (th->doff * 4) - sizeof(struct tcphdr); ptr = (const unsigned char *)(th + 1); @@ -660,6 +671,22 @@ static bool mptcp_established_options_rm_addr(struct sock *sk, return true; } +static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, + unsigned int *size, + unsigned int remaining, + struct mptcp_out_options *opts) +{ + const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); + + if (remaining < TCPOLEN_MPTCP_RST) + return; + + *size = TCPOLEN_MPTCP_RST; + opts->suboptions |= OPTION_MPTCP_RST; + opts->reset_transient = subflow->reset_transient; + opts->reset_reason = subflow->reset_reason; +} + bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, struct mptcp_out_options *opts) @@ -672,11 +699,10 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, if (unlikely(mptcp_check_fallback(sk))) return false; - /* prevent adding of any MPTCP related options on reset packet - * until we support MP_TCPRST/MP_FASTCLOSE - */ - if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) - return false; + if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) { + mptcp_established_options_rst(sk, skb, size, remaining, opts); + return true; + } if (mptcp_established_options_mp(sk, skb, &opt_size, remaining, opts)) ret = true; @@ -1137,6 +1163,12 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, ptr += 5; } + if (OPTION_MPTCP_RST & opts->suboptions) + *ptr++ = mptcp_option(MPTCPOPT_RST, + TCPOLEN_MPTCP_RST, + opts->reset_transient, + opts->reset_reason); + if (opts->ext_copy.use_ack || opts->ext_copy.use_map) { struct mptcp_ext *mpext = &opts->ext_copy; u8 len = TCPOLEN_MPTCP_DSS_BASE; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a6bd06c724d5..71e556540161 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2608,14 +2608,18 @@ bool mptcp_finish_join(struct sock *ssk) pr_debug("msk=%p, subflow=%p", msk, subflow); /* mptcp socket already closing? */ - if (!mptcp_is_fully_established(parent)) + if (!mptcp_is_fully_established(parent)) { + subflow->reset_reason = MPTCP_RST_EMPTCP; return false; + } if (!msk->pm.server_side) return true; - if (!mptcp_pm_allow_new_subflow(msk)) + if (!mptcp_pm_allow_new_subflow(msk)) { + subflow->reset_reason = MPTCP_RST_EPROHIBIT; return false; + } /* active connections are already on conn_list, and we can't acquire * msk lock here. @@ -2629,8 +2633,10 @@ bool mptcp_finish_join(struct sock *ssk) sock_hold(ssk); } spin_unlock_bh(&msk->join_list_lock); - if (!ret) + if (!ret) { + subflow->reset_reason = MPTCP_RST_EPROHIBIT; return false; + } /* attach to msk socket only after we are sure he will deal with us * at close time diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 66bd4d096753..8a247e50d326 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -23,6 +23,7 @@ #define OPTION_MPTCP_ADD_ADDR BIT(6) #define OPTION_MPTCP_ADD_ADDR6 BIT(7) #define OPTION_MPTCP_RM_ADDR BIT(8) +#define OPTION_MPTCP_RST BIT(9) /* MPTCP option subtypes */ #define MPTCPOPT_MP_CAPABLE 0 @@ -84,6 +85,18 @@ #define MPTCP_ADDR_IPVERSION_4 4 #define MPTCP_ADDR_IPVERSION_6 6 +/* MPTCP TCPRST flags */ +#define MPTCP_RST_TRANSIENT BIT(0) + +/* MPTCP Reset reason codes, rfc8684 */ +#define MPTCP_RST_EUNSPEC 0 +#define MPTCP_RST_EMPTCP 1 +#define MPTCP_RST_ERESOURCE 2 +#define MPTCP_RST_EPROHIBIT 3 +#define MPTCP_RST_EWQ2BIG 4 +#define MPTCP_RST_EBADPERF 5 +#define MPTCP_RST_EMIDDLEBOX 6 + /* MPTCP socket flags */ #define MPTCP_DATA_READY 0 #define MPTCP_NOSPACE 1 @@ -109,6 +122,7 @@ struct mptcp_options_received { u16 data_len; u16 mp_capable : 1, mp_join : 1, + reset : 1, dss : 1, add_addr : 1, rm_addr : 1, @@ -129,6 +143,8 @@ struct mptcp_options_received { __unused:2; u8 addr_id; u8 rm_id; + u8 reset_reason:4; + u8 reset_transient:1; union { struct in_addr addr; #if IS_ENABLED(CONFIG_MPTCP_IPV6) @@ -365,6 +381,8 @@ struct mptcp_subflow_context { u8 hmac[MPTCPOPT_HMAC_LEN]; u8 local_id; u8 remote_id; + u8 reset_transient:1; + u8 reset_reason:4; struct sock *tcp_sock; /* tcp sk backpointer */ struct sock *conn; /* parent mptcp_sock */ diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 1e9a72af67dc..e0da6712a5c3 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -325,8 +325,10 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) } else if (subflow->request_join) { u8 hmac[SHA256_DIGEST_SIZE]; - if (!mp_opt.mp_join) + if (!mp_opt.mp_join) { + subflow->reset_reason = MPTCP_RST_EMPTCP; goto do_reset; + } subflow->thmac = mp_opt.thmac; subflow->remote_nonce = mp_opt.nonce; @@ -335,6 +337,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) if (!subflow_thmac_valid(subflow)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC); + subflow->reset_reason = MPTCP_RST_EMPTCP; goto do_reset; } @@ -356,6 +359,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) return; do_reset: + subflow->reset_transient = 0; mptcp_subflow_reset(sk); } @@ -505,6 +509,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, struct mptcp_options_received mp_opt; bool fallback, fallback_is_fatal; struct sock *new_msk = NULL; + struct mptcp_ext *mpext; struct sock *child; pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn); @@ -565,8 +570,15 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, * to reset the context to non MPTCP status. */ if (!ctx || fallback) { - if (fallback_is_fatal) + if (fallback_is_fatal) { + mpext = skb_ext_add(skb, SKB_EXT_MPTCP); + if (mpext) { + memset(mpext, 0, sizeof(*mpext)); + mpext->reset_reason = MPTCP_RST_EMPTCP; + } + goto dispose_child; + } subflow_drop_ctx(child); goto out; @@ -600,8 +612,15 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, struct mptcp_sock *owner; owner = subflow_req->msk; - if (!owner) + if (!owner) { + mpext = skb_ext_add(skb, SKB_EXT_MPTCP); + if (mpext) { + memset(mpext, 0, sizeof(*mpext)); + mpext->reset_reason = MPTCP_RST_EPROHIBIT; + } + goto dispose_child; + } /* move the msk reference ownership to the subflow */ subflow_req->msk = NULL; @@ -936,6 +955,8 @@ static bool subflow_check_data_avail(struct sock *ssk) smp_wmb(); ssk->sk_error_report(ssk); tcp_set_state(ssk, TCP_CLOSE); + subflow->reset_transient = 0; + subflow->reset_reason = MPTCP_RST_EMPTCP; tcp_send_active_reset(ssk, GFP_ATOMIC); subflow->data_avail = 0; return false; From patchwork Thu Nov 5 17:01:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1395132 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=2001:19d0:306:5::1; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [IPv6:2001:19d0:306:5::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CRqYw0Hy9z9sRK for ; Fri, 6 Nov 2020 04:01:55 +1100 (AEDT) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 470FB16646E29; Thu, 5 Nov 2020 09:01:54 -0800 (PST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 8C78E16646E28 for ; Thu, 5 Nov 2020 09:01:51 -0800 (PST) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kaidy-0007DG-1B; Thu, 05 Nov 2020 18:01:50 +0100 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 5 Nov 2020 18:01:25 +0100 Message-Id: <20201105170126.5627-5-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201105170126.5627-1-fw@strlen.de> References: <20201105170126.5627-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: YROYBDPPG3ES6VFF7F2I3T3Y3NC6OFAO X-Message-ID-Hash: YROYBDPPG3ES6VFF7F2I3T3Y3NC6OFAO X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [PATCH MPTCP 4/5] mptcp: parse and act on incoming FASTCLOSE option List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Add parsing of FASTCLOSE option. If provided key matches the local one, worker gets scheduled and closes (tcp resets) all subflows. The MPTCP socket moves to closed state. Signed-off-by: Florian Westphal --- net/mptcp/options.c | 16 ++++++++++++++++ net/mptcp/protocol.c | 32 ++++++++++++++++++++++++++++++++ net/mptcp/protocol.h | 4 ++++ 3 files changed, 52 insertions(+) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 785a9f4e7da8..0a940687f738 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -281,6 +281,15 @@ static void mptcp_parse_option(const struct sk_buff *skb, mp_opt->rm_id = *ptr++; pr_debug("RM_ADDR: id=%d", mp_opt->rm_id); break; + case MPTCPOPT_MP_FASTCLOSE: + if (opsize != TCPOLEN_MPTCP_FASTCLOSE) + break; + + ptr += 2; + mp_opt->rcvr_key = get_unaligned_be64(ptr); + ptr += 8; + mp_opt->fastclose = 1; + break; case MPTCPOPT_RST: if (opsize != TCPOLEN_MPTCP_RST) break; @@ -309,6 +318,7 @@ void mptcp_get_options(const struct sk_buff *skb, mp_opt->mp_join = 0; mp_opt->add_addr = 0; mp_opt->ahmac = 0; + mp_opt->fastclose = 0; mp_opt->port = 0; mp_opt->rm_addr = 0; mp_opt->dss = 0; @@ -954,6 +964,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) if (!check_fully_established(msk, sk, subflow, skb, &mp_opt)) return; + if (mp_opt.fastclose && + msk->local_key == mp_opt.rcvr_key) { + WRITE_ONCE(msk->rcv_fastclose, true); + mptcp_schedule_work((struct sock *)msk); + } + if (mp_opt.add_addr && add_addr_hmac_valid(msk, &mp_opt)) { struct mptcp_addr_info addr; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 71e556540161..7e9705943813 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1849,6 +1849,35 @@ static bool mptcp_check_close_timeout(const struct sock *sk) return true; } +static noinline void mptcp_check_fastclose(struct mptcp_sock *msk) +{ + struct mptcp_subflow_context *subflow, *tmp; + struct sock *sk = &msk->sk.icsk_inet.sk; + + if (likely(!READ_ONCE(msk->rcv_fastclose))) + return; + + list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) { + struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow); + + lock_sock(tcp_sk); + subflow->reset_transient = 0; + subflow->reset_reason = MPTCP_RST_EMPTCP; + mptcp_subflow_reset(tcp_sk); + release_sock(tcp_sk); + } + + sk = (struct sock *)msk; + + inet_sk_state_store(sk, TCP_CLOSE); + sk->sk_shutdown = SHUTDOWN_MASK; + smp_mb__before_atomic(); /* SHUTDOWN must be visible first */ + set_bit(MPTCP_DATA_READY, &msk->flags); + + sk->sk_state_change(sk); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); +} + static void mptcp_worker(struct work_struct *work) { struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work); @@ -1871,6 +1900,9 @@ static void mptcp_worker(struct work_struct *work) __mptcp_close_subflow(msk); __mptcp_move_skbs(msk); + + mptcp_check_fastclose(msk); + if (mptcp_send_head(sk)) mptcp_push_pending(sk, 0); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 8a247e50d326..d4c99e091cb9 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -24,6 +24,7 @@ #define OPTION_MPTCP_ADD_ADDR6 BIT(7) #define OPTION_MPTCP_RM_ADDR BIT(8) #define OPTION_MPTCP_RST BIT(9) +#define OPTION_MPTCP_FASTCLOSE BIT(10) /* MPTCP option subtypes */ #define MPTCPOPT_MP_CAPABLE 0 @@ -59,6 +60,7 @@ #define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT 22 #define TCPOLEN_MPTCP_PORT_LEN 2 #define TCPOLEN_MPTCP_RM_ADDR_BASE 4 +#define TCPOLEN_MPTCP_FASTCLOSE 12 /* MPTCP MP_JOIN flags */ #define MPTCPOPT_BACKUP BIT(0) @@ -122,6 +124,7 @@ struct mptcp_options_received { u16 data_len; u16 mp_capable : 1, mp_join : 1, + fastclose : 1, reset : 1, dss : 1, add_addr : 1, @@ -240,6 +243,7 @@ struct mptcp_sock { bool fully_established; bool rcv_data_fin; bool snd_data_fin_enable; + bool rcv_fastclose; bool use_64bit_ack; /* Set when we received a 64-bit DSN */ spinlock_t join_list_lock; struct work_struct work; From patchwork Thu Nov 5 17:01:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1395133 X-Patchwork-Delegate: fw@strlen.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=198.145.21.10; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CRqZ039DTz9sRK for ; Fri, 6 Nov 2020 04:02:00 +1100 (AEDT) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 5B9E216646E33; Thu, 5 Nov 2020 09:01:58 -0800 (PST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id DA85B16646E2F for ; Thu, 5 Nov 2020 09:01:55 -0800 (PST) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kaie2-0007DO-7I; Thu, 05 Nov 2020 18:01:54 +0100 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 5 Nov 2020 18:01:26 +0100 Message-Id: <20201105170126.5627-6-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201105170126.5627-1-fw@strlen.de> References: <20201105170126.5627-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: 37BAXQCW5GYE3GJRC4AVQG666HQGRH4T X-Message-ID-Hash: 37BAXQCW5GYE3GJRC4AVQG666HQGRH4T X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [PATCH MPTCP 5/5] mptcp: send fastclose if userspace closes socket with unread data List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Add building & sending of FASTCLOSE option. RFC 8684 describes two methods: A): Host sends an ACK containing the MP_FASTCLOSE option on one subflow [..] On all the other subflows, Host A sends a regular TCP RST to close these subflows and tears them down. [..] R): Host A sends a RST containing the MP_FASTCLOSE option on all subflows [..]. Host A can tear down the subflows and the connection immediately. This implements option R) only: All subflows are re-set with FASTCLOSE. Signed-off-by: Florian Westphal --- net/mptcp/options.c | 35 +++++++++++++++++++++++++++++++++++ net/mptcp/protocol.c | 32 +++++++++++++++++++++++++++++++- net/mptcp/protocol.h | 1 + 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 0a940687f738..08b60d527de0 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -681,6 +681,31 @@ static bool mptcp_established_options_rm_addr(struct sock *sk, return true; } +static bool mptcp_fastclose(const struct mptcp_sock *msk) +{ + return READ_ONCE(msk->snd_fastclose); +} + +static bool mptcp_established_options_fastclose(struct sock *sk, + unsigned int *size, + unsigned int remaining, + struct mptcp_out_options *opts) +{ + const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); + + if (likely(!mptcp_fastclose(mptcp_sk(subflow->conn)))) + return false; + + if (remaining < TCPOLEN_MPTCP_FASTCLOSE) + return false; + + *size = TCPOLEN_MPTCP_FASTCLOSE; + opts->suboptions |= OPTION_MPTCP_FASTCLOSE; + opts->rcvr_key = subflow->remote_key; + + return true; +} + static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, @@ -691,6 +716,9 @@ static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_bu if (remaining < TCPOLEN_MPTCP_RST) return; + if (mptcp_established_options_fastclose(sk, size, remaining, opts)) + return; + *size = TCPOLEN_MPTCP_RST; opts->suboptions |= OPTION_MPTCP_RST; opts->reset_transient = subflow->reset_transient; @@ -1179,6 +1207,13 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, ptr += 5; } + if (OPTION_MPTCP_FASTCLOSE & opts->suboptions) { + *ptr++ = mptcp_option(MPTCPOPT_MP_FASTCLOSE, + TCPOLEN_MPTCP_FASTCLOSE, 0, 0); + put_unaligned_be64(opts->rcvr_key, ptr); + ptr += 2; + } + if (OPTION_MPTCP_RST & opts->suboptions) *ptr++ = mptcp_option(MPTCPOPT_RST, TCPOLEN_MPTCP_RST, diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7e9705943813..6b6efa00cad5 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2133,6 +2133,29 @@ static void __mptcp_check_send_data_fin(struct sock *sk) } } +static void __mptcp_send_fastclose(struct sock *sk) +{ + struct mptcp_subflow_context *subflow, *tmp; + struct mptcp_sock *msk = mptcp_sk(sk); + + WRITE_ONCE(msk->snd_fastclose, true); + + __mptcp_flush_join_list(msk); + __mptcp_clear_xmit(sk); + + WRITE_ONCE(msk->snd_nxt, msk->write_seq); + + list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) { + struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow); + + lock_sock(tcp_sk); + subflow->reset_transient = 0; + subflow->reset_reason = MPTCP_RST_EMPTCP; + mptcp_subflow_reset(tcp_sk); + release_sock(tcp_sk); + } +} + static void __mptcp_wr_shutdown(struct sock *sk) { struct mptcp_sock *msk = mptcp_sk(sk); @@ -2185,6 +2208,7 @@ static void mptcp_close(struct sock *sk, long timeout) { struct mptcp_subflow_context *subflow; bool do_cancel_work = false; + bool send_fin = false; lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; @@ -2197,7 +2221,13 @@ static void mptcp_close(struct sock *sk, long timeout) goto cleanup; } - if (mptcp_close_state(sk)) + send_fin = mptcp_close_state(sk); + if (!skb_queue_empty(&sk->sk_receive_queue)) { + __mptcp_send_fastclose(sk); + send_fin = false; + } + + if (send_fin) __mptcp_wr_shutdown(sk); sk_stream_wait_close(sk, timeout); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index d4c99e091cb9..93352044bff9 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -243,6 +243,7 @@ struct mptcp_sock { bool fully_established; bool rcv_data_fin; bool snd_data_fin_enable; + bool snd_fastclose; bool rcv_fastclose; bool use_64bit_ack; /* Set when we received a 64-bit DSN */ spinlock_t join_list_lock;