sctp: do not abandon the other frags in unsent outq if one msg has outstanding frags
authorXin Long <lucien.xin@gmail.com>
Sat, 25 Nov 2017 13:18:36 +0000 (21:18 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 1 Dec 2017 20:06:24 +0000 (15:06 -0500)
Now for the abandoned chunks in unsent outq, it would just free the chunks.
Because no tsn is assigned to them yet, there's no need to send fwd tsn to
peer, unlike for the abandoned chunks in sent outq.

The problem is when parts of the msg have been sent and the other frags
are still in unsent outq, if they are abandoned/dropped, the peer would
never get this msg reassembled.

So these frags in unsent outq can't be dropped if this msg already has
outstanding frags.

This patch does the check in sctp_chunk_abandoned and
sctp_prsctp_prune_unsent.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sctp/chunk.c
net/sctp/outqueue.c

index 9213805b558d6f7db08bfb8837319ee16c12986d..7f8baa48e7c2a834aea292106fd319c2489432a3 100644 (file)
@@ -308,6 +308,10 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
        if (chunk->msg->abandoned)
                return 1;
 
+       if (!chunk->has_tsn &&
+           !(chunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG))
+               return 0;
+
        if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
            time_after(jiffies, chunk->msg->expires_at)) {
                struct sctp_stream_out *streamout =
index 4ab164b5aad0de199a3b862f3894309531d7a338..7d67feeeffc1e758ae4be4ef1ddaea23276d1f5e 100644 (file)
@@ -407,7 +407,8 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
 
        list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) {
                if (!chk->msg->abandoned &&
-                   (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
+                   (!(chk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG) ||
+                    !SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
                     chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive))
                        continue;