Commit d87903b6 authored by Paolo Abeni's avatar Paolo Abeni Committed by Jakub Kicinski

mptcp: fix DATA_FIN generation on early shutdown

If the msk is closed before sending or receiving any data,
no DATA_FIN is generated, instead an MPC ack packet is
crafted out.

In the above scenario, the MPTCP protocol creates and sends a
pure ack and such packets matches also the criteria for an
MPC ack and the protocol tries first to insert MPC options,
leading to the described error.

This change addresses the issue by avoiding the insertion of an
MPC option for DATA_FIN packets or if the sub-flow is not
established.

To avoid doing multiple times the same test, fetch the data_fin
flag in a bool variable and pass it to both the interested
helpers.

Fixes: 6d0060f6 ("mptcp: Write MPTCP DSS headers to outgoing data packets")
Reviewed-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 341c6524
...@@ -411,6 +411,7 @@ static void clear_3rdack_retransmission(struct sock *sk) ...@@ -411,6 +411,7 @@ static void clear_3rdack_retransmission(struct sock *sk)
} }
static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
bool snd_data_fin_enable,
unsigned int *size, unsigned int *size,
unsigned int remaining, unsigned int remaining,
struct mptcp_out_options *opts) struct mptcp_out_options *opts)
...@@ -428,9 +429,10 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, ...@@ -428,9 +429,10 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
if (!skb) if (!skb)
return false; return false;
/* MPC/MPJ needed only on 3rd ack packet */ /* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */
if (subflow->fully_established || if (subflow->fully_established || snd_data_fin_enable ||
subflow->snd_isn != TCP_SKB_CB(skb)->seq) subflow->snd_isn != TCP_SKB_CB(skb)->seq ||
sk->sk_state != TCP_ESTABLISHED)
return false; return false;
if (subflow->mp_capable) { if (subflow->mp_capable) {
...@@ -502,20 +504,20 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, ...@@ -502,20 +504,20 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
} }
static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
bool snd_data_fin_enable,
unsigned int *size, unsigned int *size,
unsigned int remaining, unsigned int remaining,
struct mptcp_out_options *opts) struct mptcp_out_options *opts)
{ {
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct mptcp_sock *msk = mptcp_sk(subflow->conn); struct mptcp_sock *msk = mptcp_sk(subflow->conn);
u64 snd_data_fin_enable, ack_seq;
unsigned int dss_size = 0; unsigned int dss_size = 0;
struct mptcp_ext *mpext; struct mptcp_ext *mpext;
unsigned int ack_size; unsigned int ack_size;
bool ret = false; bool ret = false;
u64 ack_seq;
mpext = skb ? mptcp_get_ext(skb) : NULL; mpext = skb ? mptcp_get_ext(skb) : NULL;
snd_data_fin_enable = mptcp_data_fin_enabled(msk);
if (!skb || (mpext && mpext->use_map) || snd_data_fin_enable) { if (!skb || (mpext && mpext->use_map) || snd_data_fin_enable) {
unsigned int map_size; unsigned int map_size;
...@@ -717,12 +719,15 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, ...@@ -717,12 +719,15 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
unsigned int *size, unsigned int remaining, unsigned int *size, unsigned int remaining,
struct mptcp_out_options *opts) struct mptcp_out_options *opts)
{ {
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
unsigned int opt_size = 0; unsigned int opt_size = 0;
bool snd_data_fin;
bool ret = false; bool ret = false;
opts->suboptions = 0; opts->suboptions = 0;
if (unlikely(mptcp_check_fallback(sk))) if (unlikely(__mptcp_check_fallback(msk)))
return false; return false;
/* prevent adding of any MPTCP related options on reset packet /* prevent adding of any MPTCP related options on reset packet
...@@ -731,10 +736,10 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, ...@@ -731,10 +736,10 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST))
return false; return false;
if (mptcp_established_options_mp(sk, skb, &opt_size, remaining, opts)) snd_data_fin = mptcp_data_fin_enabled(msk);
if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts))
ret = true; ret = true;
else if (mptcp_established_options_dss(sk, skb, &opt_size, remaining, else if (mptcp_established_options_dss(sk, skb, snd_data_fin, &opt_size, remaining, opts))
opts))
ret = true; ret = true;
/* we reserved enough space for the above options, and exceeding the /* we reserved enough space for the above options, and exceeding the
......
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