summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2008-01-15 11:41:56 -0500
committerVlad Yasevich <vladislav.yasevich@hp.com>2008-02-06 21:26:26 -0500
commitc068be5491924c1c1c37dc046f36976c27bc7bb2 (patch)
tree05212f5704d2c1aa66629ac20ac312d0af39eca1 /net
parent01f2d38498957e967cd6f6011a6b208393957b4a (diff)
downloadlinux-c068be5491924c1c1c37dc046f36976c27bc7bb2.tar.bz2
[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>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/ulpqueue.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index d300f4973a79..5061a26c5028 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -874,6 +874,7 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
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 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
/* 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 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
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 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
__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.
*/