> On May 31, 2026, at 9:11 PM, Matthieu Baerts (NGI0) <[email protected]> > wrote: > > From: Paolo Abeni <[email protected]> > > The MPTCP output path access locklessly the MPTCP-level ack_seq > in multiple times, using possibly different values for the data_ack > in the DSS option and to compute the announced rcv wnd for the same > packet. > > Refactor the cote to avoid inconsistencies which may confuse the > peer. Also ensure that the MPTCP level rcv wnd is updated only when > the egress packet actually contains a DSS ack. > > Fixes: fa3fe2b15031 ("mptcp: track window announced to peer") > Cc: [email protected] > Signed-off-by: Paolo Abeni <[email protected]> > Reviewed-by: Matthieu Baerts (NGI0) <[email protected]> > Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> > --- > net/mptcp/options.c | 36 ++++++++++++++++++------------------ > 1 file changed, 18 insertions(+), 18 deletions(-) > > diff --git a/net/mptcp/options.c b/net/mptcp/options.c > index 8a1c5698983c..5c228344e83f 100644 > --- a/net/mptcp/options.c > +++ b/net/mptcp/options.c > @@ -570,7 +570,6 @@ static bool mptcp_established_options_dss(struct sock > *sk, struct sk_buff *skb, > struct mptcp_ext *mpext; > unsigned int ack_size; > bool ret = false; > - u64 ack_seq; > > opts->csum_reqd = READ_ONCE(msk->csum_enabled); > mpext = skb ? mptcp_get_ext(skb) : NULL; > @@ -601,14 +600,11 @@ static bool mptcp_established_options_dss(struct sock > *sk, struct sk_buff *skb, > return ret; > } > > - ack_seq = READ_ONCE(msk->ack_seq); > if (READ_ONCE(msk->use_64bit_ack)) { > ack_size = TCPOLEN_MPTCP_DSS_ACK64; > - opts->ext_copy.data_ack = ack_seq; > opts->ext_copy.ack64 = 1; > } else { > ack_size = TCPOLEN_MPTCP_DSS_ACK32; > - opts->ext_copy.data_ack32 = (uint32_t)ack_seq; > opts->ext_copy.ack64 = 0; > } > opts->ext_copy.use_ack = 1; > @@ -1297,19 +1293,14 @@ bool mptcp_incoming_options(struct sock *sk, struct > sk_buff *skb) > return true; > } > > -static void mptcp_set_rwin(struct tcp_sock *tp, struct tcphdr *th) > +static u64 mptcp_set_rwin(struct mptcp_sock *msk, struct tcp_sock *tp, > + struct tcphdr *th, u64 ack_seq) > { > const struct sock *ssk = (const struct sock *)tp; > - struct mptcp_subflow_context *subflow; > - u64 ack_seq, rcv_wnd_old, rcv_wnd_new; > - struct mptcp_sock *msk; > + u64 rcv_wnd_old, rcv_wnd_new; > u32 new_win; > u64 win; > > - subflow = mptcp_subflow_ctx(ssk); > - msk = mptcp_sk(subflow->conn); > - > - ack_seq = READ_ONCE(msk->ack_seq); > rcv_wnd_new = ack_seq + tp->rcv_wnd; > > rcv_wnd_old = atomic64_read(&msk->rcv_wnd_sent); > @@ -1362,7 +1353,7 @@ static void mptcp_set_rwin(struct tcp_sock *tp, struct > tcphdr *th) > > update_wspace: > WRITE_ONCE(msk->old_wspace, tp->rcv_wnd); > - subflow->rcv_wnd_sent = rcv_wnd_new; > + return rcv_wnd_new; > } > > static void mptcp_track_rwin(struct tcp_sock *tp) > @@ -1474,13 +1465,25 @@ void mptcp_write_options(struct tcphdr *th, __be32 > *ptr, struct tcp_sock *tp, > *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags); > > if (mpext->use_ack) { > + struct mptcp_sock *msk; > + u64 ack_seq; > + > + /* DSS option is set only by mptcp_established_option, > + * the caller is __tcp_transmit_skb() and ssk is always > + * not NULL. > + */ > + subflow = mptcp_subflow_ctx(ssk); > + msk = mptcp_sk(subflow->conn); > + ack_seq = READ_ONCE(msk->ack_seq); > if (mpext->ack64) { > - put_unaligned_be64(mpext->data_ack, ptr); > + put_unaligned_be64(ack_seq, ptr); > ptr += 2; > } else { > - put_unaligned_be32(mpext->data_ack32, ptr); > + put_unaligned_be32(ack_seq, ptr); > ptr += 1; > } > + subflow->rcv_wnd_sent = mptcp_set_rwin(msk, tp, th, > + ack_seq); > } > > if (mpext->use_map) { > @@ -1708,9 +1711,6 @@ void mptcp_write_options(struct tcphdr *th, __be32 > *ptr, struct tcp_sock *tp, > i += 4; > } > } > - > - if (tp) > - mptcp_set_rwin(tp, th); > } > > __be32 mptcp_get_reset_option(const struct sk_buff *skb) > > -- > 2.53.0 > >

