patch-2.4.27 linux-2.4.27/net/sctp/ulpqueue.c

Next file: linux-2.4.27/net/wanrouter/wanproc.c
Previous file: linux-2.4.27/net/sctp/ulpevent.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.26/net/sctp/ulpqueue.c linux-2.4.27/net/sctp/ulpqueue.c
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
@@ -79,7 +79,7 @@
 struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
 				 struct sctp_association *asoc)
 {
-	memset(ulpq, sizeof(struct sctp_ulpq), 0x00);
+	memset(ulpq, 0, sizeof(struct sctp_ulpq));
 
 	ulpq->asoc = asoc;
 	skb_queue_head_init(&ulpq->reasm);
@@ -251,7 +251,7 @@
 	struct sctp_ulpevent *cevent;
 	__u32 tsn, ctsn;
 
-	tsn = event->sndrcvinfo.sinfo_tsn;
+	tsn = event->tsn;
 
 	/* See if it belongs at the end. */
 	pos = skb_peek_tail(&ulpq->reasm);
@@ -262,7 +262,7 @@
 
 	/* Short circuit just dropping it at the end. */
 	cevent = sctp_skb2event(pos);
-	ctsn = cevent->sndrcvinfo.sinfo_tsn;
+	ctsn = cevent->tsn;
 	if (TSN_lt(ctsn, tsn)) {
 		__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
 		return;
@@ -271,7 +271,7 @@
 	/* Find the right place in this list. We store them by TSN.  */
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		if (TSN_lt(tsn, ctsn))
 			break;
@@ -368,7 +368,7 @@
 	 */
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_FIRST_FRAG:
@@ -425,7 +425,7 @@
 
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_MIDDLE_FRAG:
@@ -486,7 +486,7 @@
 		/* Do not even bother unless this is the next tsn to
 		 * be delivered.
 		 */
-		ctsn = event->sndrcvinfo.sinfo_tsn;
+		ctsn = event->tsn;
 		ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map);
 		if (TSN_lte(ctsn, ctsnap))
 			retval = sctp_ulpq_retrieve_partial(ulpq);
@@ -517,7 +517,7 @@
 
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_FIRST_FRAG:
@@ -563,15 +563,15 @@
 	__u16 sid, csid;
 	__u16 ssn, cssn;
 
-	sid = event->sndrcvinfo.sinfo_stream;
-	ssn = event->sndrcvinfo.sinfo_ssn;
+	sid = event->stream;
+	ssn = event->ssn;
 	in  = &ulpq->asoc->ssnmap->in;
 
 	/* We are holding the chunks by stream, by SSN.  */
 	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
 		cevent = (struct sctp_ulpevent *) pos->cb;
-		csid = cevent->sndrcvinfo.sinfo_stream;
-		cssn = cevent->sndrcvinfo.sinfo_ssn;
+		csid = cevent->stream;
+		cssn = cevent->ssn;
 
 		/* Have we gone too far?  */
 		if (csid > sid)
@@ -609,12 +609,12 @@
 		return;
 	}
 
-	sid = event->sndrcvinfo.sinfo_stream;
-	ssn = event->sndrcvinfo.sinfo_ssn;
+	sid = event->stream;
+	ssn = event->ssn;
 	
 	cevent = (struct sctp_ulpevent *) pos->cb;
-	csid = cevent->sndrcvinfo.sinfo_stream;
-	cssn = cevent->sndrcvinfo.sinfo_ssn;
+	csid = cevent->stream;
+	cssn = cevent->ssn;
 	if (sid > csid) {
 		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
 		return;
@@ -630,8 +630,8 @@
 	 */
 	skb_queue_walk(&ulpq->lobby, pos) {
 		cevent = (struct sctp_ulpevent *) pos->cb;
-		csid = cevent->sndrcvinfo.sinfo_stream;
-		cssn = cevent->sndrcvinfo.sinfo_ssn;
+		csid = cevent->stream;
+		cssn = cevent->ssn;
 
 		if (csid > sid)
 			break;
@@ -656,8 +656,8 @@
 		return event;
 
 	/* Note: The stream ID must be verified before this routine.  */
-	sid = event->sndrcvinfo.sinfo_stream;
-	ssn = event->sndrcvinfo.sinfo_ssn;
+	sid = event->stream;
+	ssn = event->ssn;
 	in  = &ulpq->asoc->ssnmap->in;
 
 	/* Is this the expected SSN for this stream ID?  */
@@ -680,6 +680,71 @@
 	return event;
 }
 
+/* Helper function to gather skbs that have possibly become
+ * ordered by forward tsn skipping their dependencies.
+ */
+static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
+{
+	struct sk_buff *pos, *tmp;
+	struct sctp_ulpevent *cevent;
+	struct sctp_ulpevent *event = NULL;
+	struct sctp_stream *in;
+	struct sk_buff_head temp;
+	__u16 csid, cssn;
+
+	in  = &ulpq->asoc->ssnmap->in;
+
+	/* We are holding the chunks by stream, by SSN.  */
+	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
+		cevent = (struct sctp_ulpevent *) pos->cb;
+		csid = cevent->stream;
+		cssn = cevent->ssn;
+
+		if (cssn != sctp_ssn_peek(in, csid))
+			break;
+
+		/* Found it, so mark in the ssnmap. */	       
+		sctp_ssn_next(in, csid);
+
+		__skb_unlink(pos, pos->list);
+		if (!event) {						
+			/* Create a temporary list to collect chunks on.  */
+			event = sctp_skb2event(pos);
+			skb_queue_head_init(&temp);
+			__skb_queue_tail(&temp, sctp_event2skb(event));
+		} else {
+			/* Attach all gathered skbs to the event.  */
+			__skb_queue_tail(sctp_event2skb(event)->list, pos);
+		}
+	}
+
+	/* Send event to the ULP.  */
+	if (event)
+		sctp_ulpq_tail_event(ulpq, event);
+}
+
+/* Skip over an SSN. */
+void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
+{
+	struct sctp_stream *in;
+
+	/* Note: The stream ID must be verified before this routine.  */
+	in  = &ulpq->asoc->ssnmap->in;
+
+	/* Is this an old SSN?  If so ignore. */
+	if (SSN_lt(ssn, sctp_ssn_peek(in, sid)))
+		return;
+
+	/* Mark that we are no longer expecting this SSN or lower. */
+	sctp_ssn_skip(in, sid, ssn);
+
+	/* Go find any other chunks that were waiting for
+	 * ordering and deliver them if needed. 
+	 */
+	sctp_ulpq_reap_ordered(ulpq);
+	return;
+}
+
 /* Renege 'needed' bytes from the ordering queue. */
 static __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed)
 {
@@ -694,7 +759,7 @@
 	while ((skb = __skb_dequeue_tail(&ulpq->lobby))) {
 		freed += skb_headlen(skb);
 		event = sctp_skb2event(skb);
-		tsn = event->sndrcvinfo.sinfo_tsn;
+		tsn = event->tsn;
 
 		sctp_ulpevent_free(event);
 		sctp_tsnmap_renege(tsnmap, tsn);
@@ -720,7 +785,7 @@
 	while ((skb = __skb_dequeue_tail(&ulpq->reasm))) {
 		freed += skb_headlen(skb);
 		event = sctp_skb2event(skb);
-		tsn = event->sndrcvinfo.sinfo_tsn;
+		tsn = event->tsn;
 
 		sctp_ulpevent_free(event);
 		sctp_tsnmap_renege(tsnmap, tsn);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)