svn commit: r216188 - head/sys/netinet

Michael Tuexen tuexen at FreeBSD.org
Sat Dec 4 19:29:50 UTC 2010


Author: tuexen
Date: Sat Dec  4 19:29:49 2010
New Revision: 216188
URL: http://svn.freebsd.org/changeset/base/216188

Log:
  Fix a bug where also the number of non-renegable gap reports
  was considered to be potentially renegable.
  
  MFC after: 1 day.

Modified:
  head/sys/netinet/sctp_indata.c
  head/sys/netinet/sctp_input.c
  head/sys/netinet/sctp_structs.h

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c	Sat Dec  4 18:52:05 2010	(r216187)
+++ head/sys/netinet/sctp_indata.c	Sat Dec  4 19:29:49 2010	(r216188)
@@ -3081,14 +3081,17 @@ sctp_handle_segments(struct mbuf *m, int
 	int num_frs = 0;
 	int chunk_freed;
 	int non_revocable;
-	uint16_t frag_strt, frag_end;
-	uint32_t last_frag_high;
+	uint16_t frag_strt, frag_end, prev_frag_end;
 
-	tp1 = NULL;
-	last_frag_high = 0;
+	tp1 = TAILQ_FIRST(&asoc->sent_queue);
+	prev_frag_end = 0;
 	chunk_freed = 0;
 
 	for (i = 0; i < (num_seg + num_nr_seg); i++) {
+		if (i == num_seg) {
+			prev_frag_end = 0;
+			tp1 = TAILQ_FIRST(&asoc->sent_queue);
+		}
 		frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
 		    sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
 		*offset += sizeof(block);
@@ -3097,58 +3100,29 @@ sctp_handle_segments(struct mbuf *m, int
 		}
 		frag_strt = ntohs(frag->start);
 		frag_end = ntohs(frag->end);
-		/* some sanity checks on the fragment offsets */
+
 		if (frag_strt > frag_end) {
-			/* this one is malformed, skip */
+			/* This gap report is malformed, skip it. */
 			continue;
 		}
-		if (compare_with_wrap((frag_end + last_tsn), *biggest_tsn_acked,
-		    MAX_TSN))
-			*biggest_tsn_acked = frag_end + last_tsn;
-
-		/* mark acked dgs and find out the highestTSN being acked */
-		if (tp1 == NULL) {
+		if (frag_strt <= prev_frag_end) {
+			/* This gap report is not in order, so restart. */
 			tp1 = TAILQ_FIRST(&asoc->sent_queue);
-			/* save the locations of the last frags */
-			last_frag_high = frag_end + last_tsn;
-		} else {
-			/*
-			 * now lets see if we need to reset the queue due to
-			 * a out-of-order SACK fragment
-			 */
-			if (compare_with_wrap(frag_strt + last_tsn,
-			    last_frag_high, MAX_TSN)) {
-				/*
-				 * if the new frag starts after the last TSN
-				 * frag covered, we are ok and this one is
-				 * beyond the last one
-				 */
-				;
-			} else {
-				/*
-				 * ok, they have reset us, so we need to
-				 * reset the queue this will cause extra
-				 * hunting but hey, they chose the
-				 * performance hit when they failed to order
-				 * their gaps
-				 */
-				tp1 = TAILQ_FIRST(&asoc->sent_queue);
-			}
-			last_frag_high = frag_end + last_tsn;
+		}
+		if (compare_with_wrap((last_tsn + frag_end), *biggest_tsn_acked, MAX_TSN)) {
+			*biggest_tsn_acked = last_tsn + frag_end;
 		}
 		if (i < num_seg) {
 			non_revocable = 0;
 		} else {
 			non_revocable = 1;
 		}
-		if (i == num_seg) {
-			tp1 = NULL;
-		}
 		if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
 		    non_revocable, &num_frs, biggest_newly_acked_tsn,
 		    this_sack_lowest_newack, ecn_seg_sums)) {
 			chunk_freed = 1;
 		}
+		prev_frag_end = frag_end;
 	}
 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
 		if (num_frs)
@@ -4817,7 +4791,7 @@ sctp_handle_sack(struct mbuf *m, int off
 		}
 	}
 	/********************************************/
-	/* drop the acked chunks from the sendqueue */
+	/* drop the acked chunks from the sentqueue */
 	/********************************************/
 	asoc->last_acked_seq = cum_ack;
 
@@ -4925,9 +4899,10 @@ done_with_it:
 	 * we had some before and now we have NONE.
 	 */
 
-	if (num_seg)
+	if (num_seg) {
 		sctp_check_for_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
-	else if (asoc->saw_sack_with_frags) {
+		asoc->saw_sack_with_frags = 1;
+	} else if (asoc->saw_sack_with_frags) {
 		int cnt_revoked = 0;
 
 		tp1 = TAILQ_FIRST(&asoc->sent_queue);
@@ -4963,10 +4938,10 @@ done_with_it:
 		}
 		asoc->saw_sack_with_frags = 0;
 	}
-	if (num_seg || num_nr_seg)
-		asoc->saw_sack_with_frags = 1;
+	if (num_nr_seg > 0)
+		asoc->saw_sack_with_nr_frags = 1;
 	else
-		asoc->saw_sack_with_frags = 0;
+		asoc->saw_sack_with_nr_frags = 0;
 
 	/* JRS - Use the congestion control given in the CC module */
 	asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);

Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c	Sat Dec  4 18:52:05 2010	(r216187)
+++ head/sys/netinet/sctp_input.c	Sat Dec  4 19:29:49 2010	(r216188)
@@ -4644,6 +4644,7 @@ process_control_chunks:
 				    ((compare_with_wrap(cum_ack, stcb->asoc.last_acked_seq, MAX_TSN)) ||
 				    (cum_ack == stcb->asoc.last_acked_seq)) &&
 				    (stcb->asoc.saw_sack_with_frags == 0) &&
+				    (stcb->asoc.saw_sack_with_nr_frags == 0) &&
 				    (!TAILQ_EMPTY(&stcb->asoc.sent_queue))
 				    ) {
 					/*
@@ -4737,6 +4738,7 @@ process_control_chunks:
 				    ((compare_with_wrap(cum_ack, stcb->asoc.last_acked_seq, MAX_TSN)) ||
 				    (cum_ack == stcb->asoc.last_acked_seq)) &&
 				    (stcb->asoc.saw_sack_with_frags == 0) &&
+				    (stcb->asoc.saw_sack_with_nr_frags == 0) &&
 				    (!TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
 					/*
 					 * We have a SIMPLE sack having no

Modified: head/sys/netinet/sctp_structs.h
==============================================================================
--- head/sys/netinet/sctp_structs.h	Sat Dec  4 18:52:05 2010	(r216187)
+++ head/sys/netinet/sctp_structs.h	Sat Dec  4 19:29:49 2010	(r216188)
@@ -1058,6 +1058,7 @@ struct sctp_association {
 	uint8_t delayed_connection;
 	uint8_t ifp_had_enobuf;
 	uint8_t saw_sack_with_frags;
+	uint8_t saw_sack_with_nr_frags;
 	uint8_t in_asocid_hash;
 	uint8_t assoc_up_sent;
 	uint8_t adaptation_needed;


More information about the svn-src-all mailing list