[SCTP]: Correctly reap SSNs when processing FORWARD_TSN chunk
When we recieve a FORWARD_TSN chunk, we need to reap
all the queued fast-forwarded chunks from the ordering queue
However, if we don't have them queued, we need to see if
the next expected one is there as well. If it is, start
deliver from that point instead of waiting for the next
chunk to arrive.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index d300f49..5061a26 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -874,6 +874,7 @@
struct sctp_ulpevent *event;
struct sctp_stream *in;
struct sk_buff_head temp;
+ struct sk_buff_head *lobby = &ulpq->lobby;
__u16 csid, cssn;
in = &ulpq->asoc->ssnmap->in;
@@ -881,7 +882,7 @@
/* We are holding the chunks by stream, by SSN. */
skb_queue_head_init(&temp);
event = NULL;
- sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
+ sctp_skb_for_each(pos, lobby, tmp) {
cevent = (struct sctp_ulpevent *) pos->cb;
csid = cevent->stream;
cssn = cevent->ssn;
@@ -895,10 +896,10 @@
continue;
/* see if this ssn has been marked by skipping */
- if (!SSN_lte(cssn, sctp_ssn_peek(in, csid)))
+ if (!SSN_lt(cssn, sctp_ssn_peek(in, csid)))
break;
- __skb_unlink(pos, &ulpq->lobby);
+ __skb_unlink(pos, lobby);
if (!event)
/* Create a temporary list to collect chunks on. */
event = sctp_skb2event(pos);
@@ -907,6 +908,22 @@
__skb_queue_tail(&temp, pos);
}
+ /* If we didn't reap any data, see if the next expected SSN
+ * is next on the queue and if so, use that.
+ */
+ if (event == NULL && pos != (struct sk_buff *)lobby) {
+ cevent = (struct sctp_ulpevent *) pos->cb;
+ csid = cevent->stream;
+ cssn = cevent->ssn;
+
+ if (csid == sid && cssn == sctp_ssn_peek(in, csid)) {
+ sctp_ssn_next(in, csid);
+ __skb_unlink(pos, lobby);
+ __skb_queue_tail(&temp, pos);
+ event = sctp_skb2event(pos);
+ }
+ }
+
/* Send event to the ULP. 'event' is the sctp_ulpevent for
* very first SKB on the 'temp' list.
*/