From: Shardul Bankar <[email protected]>

When a packet arrives with map_seq < ack_seq < end_seq, the beginning
of the packet has already been acknowledged but the end contains new
data. Currently the entire packet is dropped as "old data," forcing
the sender to retransmit.

Instead, skip the already-acked bytes by adjusting the skb offset and
enqueue only the new portion. Update bytes_received and ack_seq to
reflect the new data consumed.

A previous attempt at this fix has been sent by Paolo Abeni [1], but had
issues [2]: it also added a zero-window check and changed rcv_wnd_sent
initialization, which caused test regressions. This version addresses
only the partial packet handling without modifying receive window
accounting.

Fixes: ab174ad8ef76 ("mptcp: move ooo skbs into msk out of order queue.")
Cc: [email protected]
Link: 
https://lore.kernel.org/c9b426a4e163aa3c4fe8b80c79f1a610f47ae7d8.1763075056.git.pab...@redhat.com
 [1]
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/600 [2]
Signed-off-by: Shardul Bankar <[email protected]>
[[email protected]: update map]
Signed-off-by: Paolo Abeni <[email protected]>
Reviewed-by: Matthieu Baerts (NGI0) <[email protected]>
Signed-off-by: Matthieu Baerts (NGI0) <[email protected]>
---
v3: (Paolo)
  - update map_seq, too (AI tool)
v2: (Shardul)
  - Drop the mptcp_try_coalesce() attempt for partial packets, since
    non-zero offset always prevents coalescing (Paolo).
  - https://lore.kernel.org/[email protected]
v1: (Shardul)
  - https://lore.kernel.org/[email protected]
v0: (Paolo)
  - 
https://lore.kernel.org/mptcp/c9b426a4e163aa3c4fe8b80c79f1a610f47ae7d8.1763075056.git.pab...@redhat.com
---
 net/mptcp/protocol.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 4546a8b09884..859df49e16dc 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -397,12 +397,26 @@ static bool __mptcp_move_skb(struct sock *sk, struct 
sk_buff *skb)
                return false;
        }
 
-       /* old data, keep it simple and drop the whole pkt, sender
-        * will retransmit as needed, if needed.
+       /* Completely old data? */
+       if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) {
+               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
+               mptcp_drop(sk, skb);
+               return false;
+       }
+
+       /* Partial packet: map_seq < ack_seq < end_seq.
+        * Skip the already-acked bytes and enqueue the new data.
         */
-       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
-       mptcp_drop(sk, skb);
-       return false;
+       copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
+       MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;
+       MPTCP_SKB_CB(skb)->map_seq += msk->ack_seq -
+                                     MPTCP_SKB_CB(skb)->map_seq;
+       msk->bytes_received += copy_len;
+       WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
+
+       skb_set_owner_r(skb, sk);
+       __skb_queue_tail(&sk->sk_receive_queue, skb);
+       return true;
 }
 
 static void mptcp_stop_rtx_timer(struct sock *sk)

-- 
2.53.0


Reply via email to