summaryrefslogtreecommitdiff
path: root/net/sctp/stream_interleave.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-11-10 19:28:27 -0800
committerDavid S. Miller <davem@davemloft.net>2018-11-10 19:28:27 -0800
commit348bbc25c40844c5efa083a3842c7f53d70a815e (patch)
treecea1c8ab0d2ebc06f38790b3f84411281003f29d /net/sctp/stream_interleave.c
parent9e733177c71a81ae9be22dbacc79a0dd60a99f21 (diff)
downloadlwn-348bbc25c40844c5efa083a3842c7f53d70a815e.tar.gz
lwn-348bbc25c40844c5efa083a3842c7f53d70a815e.zip
sctp: Fix SKB list traversal in sctp_intl_store_reasm().
To be fully correct, an iterator has an undefined value when something like skb_queue_walk() naturally terminates. This will actually matter when SKB queues are converted over to list_head. Formalize what this code ends up doing with the current implementation. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/stream_interleave.c')
-rw-r--r--net/sctp/stream_interleave.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/net/sctp/stream_interleave.c b/net/sctp/stream_interleave.c
index 0a78cdf86463..368d9c33fde1 100644
--- a/net/sctp/stream_interleave.c
+++ b/net/sctp/stream_interleave.c
@@ -140,7 +140,7 @@ static void sctp_intl_store_reasm(struct sctp_ulpq *ulpq,
struct sctp_ulpevent *event)
{
struct sctp_ulpevent *cevent;
- struct sk_buff *pos;
+ struct sk_buff *pos, *loc;
pos = skb_peek_tail(&ulpq->reasm);
if (!pos) {
@@ -166,23 +166,30 @@ static void sctp_intl_store_reasm(struct sctp_ulpq *ulpq,
return;
}
+ loc = NULL;
skb_queue_walk(&ulpq->reasm, pos) {
cevent = sctp_skb2event(pos);
if (event->stream < cevent->stream ||
(event->stream == cevent->stream &&
- MID_lt(event->mid, cevent->mid)))
+ MID_lt(event->mid, cevent->mid))) {
+ loc = pos;
break;
-
+ }
if (event->stream == cevent->stream &&
event->mid == cevent->mid &&
!(cevent->msg_flags & SCTP_DATA_FIRST_FRAG) &&
(event->msg_flags & SCTP_DATA_FIRST_FRAG ||
- event->fsn < cevent->fsn))
+ event->fsn < cevent->fsn)) {
+ loc = pos;
break;
+ }
}
- __skb_queue_before(&ulpq->reasm, pos, sctp_event2skb(event));
+ if (!loc)
+ __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
+ else
+ __skb_queue_before(&ulpq->reasm, loc, sctp_event2skb(event));
}
static struct sctp_ulpevent *sctp_intl_retrieve_partial(