svn commit: r190689 - head/sys/netinet

Randall Stewart rrs at FreeBSD.org
Sat Apr 4 04:43:33 PDT 2009


Author: rrs
Date: Sat Apr  4 11:43:32 2009
New Revision: 190689
URL: http://svn.freebsd.org/changeset/base/190689

Log:
  Many bug fixes (from the IETF hack-fest):
  - PR-SCTP had major issues when skipping through a multi-part message.
    o Did not look at socket buffer.
    o Did not properly handle the reassmebly queue.
    o The MARKED segments could interfere and un-skip a chunk causing
      a problem with the proper FWD-TSN.
    o No FR of FWD-TSN's was being done.
  - NR-Sack code was basically disabled. It needed fixes that
    never got into the real code.
  - CMT code had issues when the two paths were NOT the same b/w. We
    found a few small bugs, but also the critcal one here was not
    dividing the rwnd amongst the paths.
  
  Obtained from:	Michael Tuexen and myself at the IETF hack-fest ;-)

Modified:
  head/sys/netinet/sctp_indata.c
  head/sys/netinet/sctp_input.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_sysctl.c
  head/sys/netinet/sctp_sysctl.h
  head/sys/netinet/sctp_uio.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c	Sat Apr  4 11:23:00 2009	(r190688)
+++ head/sys/netinet/sctp_indata.c	Sat Apr  4 11:43:32 2009	(r190689)
@@ -423,12 +423,13 @@ abandon:
 		if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
 
 			nr_tsn = chk->rec.data.TSN_seq;
-			if (nr_tsn >= asoc->nr_mapping_array_base_tsn) {
+			if ((compare_with_wrap(nr_tsn, asoc->nr_mapping_array_base_tsn, MAX_TSN)) ||
+			    (nr_tsn == asoc->nr_mapping_array_base_tsn)) {
 				nr_gap = nr_tsn - asoc->nr_mapping_array_base_tsn;
 			} else {
 				nr_gap = (MAX_TSN - asoc->nr_mapping_array_base_tsn) + nr_tsn + 1;
 			}
-			if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
+			if ((nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3)) ||
 			    (nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
 				/*
 				 * EY The 1st should never happen, as in
@@ -440,10 +441,11 @@ abandon:
 				 * nr_mapping_array is always expanded when
 				 * mapping_array is expanded
 				 */
+				printf("Impossible nr_gap ack range failed\n");
 			} else {
 				SCTP_TCB_LOCK_ASSERT(stcb);
 				SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
-				if (nr_tsn > asoc->highest_tsn_inside_nr_map)
+				if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
 					asoc->highest_tsn_inside_nr_map = nr_tsn;
 			}
 		}
@@ -550,7 +552,9 @@ abandon:
 							} else {
 								SCTP_TCB_LOCK_ASSERT(stcb);
 								SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
-								if (nr_tsn > asoc->highest_tsn_inside_nr_map)
+								if (compare_with_wrap(nr_tsn,
+								    asoc->highest_tsn_inside_nr_map,
+								    MAX_TSN))
 									asoc->highest_tsn_inside_nr_map = nr_tsn;
 							}
 						}
@@ -699,7 +703,7 @@ protocol_error:
 			} else {
 				SCTP_TCB_LOCK_ASSERT(stcb);
 				SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
-				if (nr_tsn > asoc->highest_tsn_inside_nr_map)
+				if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
 					asoc->highest_tsn_inside_nr_map = nr_tsn;
 			}
 		}
@@ -760,7 +764,8 @@ protocol_error:
 					} else {
 						SCTP_TCB_LOCK_ASSERT(stcb);
 						SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
-						if (nr_tsn > asoc->highest_tsn_inside_nr_map)
+						if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map,
+						    MAX_TSN))
 							asoc->highest_tsn_inside_nr_map = nr_tsn;
 					}
 				}
@@ -2390,6 +2395,15 @@ finish_express_del:
 	}
 	SCTP_TCB_LOCK_ASSERT(stcb);
 	SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
+
+	if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
+	    asoc->peer_supports_nr_sack &&
+	    (SCTP_BASE_SYSCTL(sctp_do_drain) == 0)) {
+		SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
+		if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
+			asoc->highest_tsn_inside_nr_map = tsn;
+		}
+	}
 	/* check the special flag for stream resets */
 	if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
 	    ((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) ||
@@ -2498,9 +2512,9 @@ sctp_sack_check(struct sctp_tcb *stcb, i
 	int slide_from, slide_end, lgap, distance;
 
 	/* EY nr_mapping array variables */
-	int nr_at;
-	int nr_last_all_ones = 0;
-	int nr_slide_from, nr_slide_end, nr_lgap, nr_distance;
+	/* int nr_at; */
+	/* int nr_last_all_ones = 0; */
+	/* int nr_slide_from, nr_slide_end, nr_lgap, nr_distance; */
 
 	uint32_t old_cumack, old_base, old_highest;
 	unsigned char aux_array[64];
@@ -2683,102 +2697,19 @@ sctp_sack_check(struct sctp_tcb *stcb, i
 				    asoc->cumulative_tsn, asoc->highest_tsn_inside_map,
 				    SCTP_MAP_SLIDE_RESULT);
 			}
-		}
-	}
-	/*
-	 * EY if doing nr_sacks then slide the nr_mapping_array accordingly
-	 * please
-	 */
-	if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
-
-		nr_at = 0;
-		for (nr_slide_from = 0; nr_slide_from < stcb->asoc.nr_mapping_array_size; nr_slide_from++) {
-
-			if (asoc->nr_mapping_array[nr_slide_from] == 0xff) {
-				nr_at += 8;
-				nr_last_all_ones = 1;
-			} else {
-				/* there is a 0 bit */
-				nr_at += sctp_map_lookup_tab[asoc->nr_mapping_array[nr_slide_from]];
-				nr_last_all_ones = 0;
-				break;
-			}
-		}
-
-		nr_at++;
-
-		if (compare_with_wrap(asoc->cumulative_tsn,
-		    asoc->highest_tsn_inside_nr_map, MAX_TSN) && (at >= 8)) {
-			/* The complete array was completed by a single FR */
-			/* higest becomes the cum-ack */
-			int clr;
-
-			clr = (nr_at >> 3) + 1;
-
-			if (clr > asoc->nr_mapping_array_size)
-				clr = asoc->nr_mapping_array_size;
-
-			memset(asoc->nr_mapping_array, 0, clr);
-			/* base becomes one ahead of the cum-ack */
-			asoc->nr_mapping_array_base_tsn = asoc->cumulative_tsn + 1;
-			asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn;
-
-		} else if (nr_at >= 8) {
-			/* we can slide the mapping array down */
-			/* Calculate the new byte postion we can move down */
-
 			/*
-			 * now calculate the ceiling of the move using our
-			 * highest TSN value
+			 * EY if doing nr_sacks then slide the
+			 * nr_mapping_array accordingly please
 			 */
-			if (asoc->highest_tsn_inside_nr_map >= asoc->nr_mapping_array_base_tsn) {
-				nr_lgap = asoc->highest_tsn_inside_nr_map -
-				    asoc->nr_mapping_array_base_tsn;
-			} else {
-				nr_lgap = (MAX_TSN - asoc->nr_mapping_array_base_tsn) +
-				    asoc->highest_tsn_inside_nr_map + 1;
-			}
-			nr_slide_end = nr_lgap >> 3;
-			if (nr_slide_end < nr_slide_from) {
-#ifdef INVARIANTS
-				panic("impossible slide");
-#else
-				printf("impossible slide?\n");
-				return;
-#endif
-			}
-			if (nr_slide_end > asoc->nr_mapping_array_size) {
-#ifdef INVARIANTS
-				panic("would overrun buffer");
-#else
-				printf("Gak, would have overrun map end:%d nr_slide_end:%d\n",
-				    asoc->nr_mapping_array_size, nr_slide_end);
-				nr_slide_end = asoc->nr_mapping_array_size;
-#endif
-			}
-			nr_distance = (nr_slide_end - nr_slide_from) + 1;
-
-			if (nr_distance + nr_slide_from > asoc->nr_mapping_array_size ||
-			    nr_distance < 0) {
-				/*
-				 * Here we do NOT slide forward the array so
-				 * that hopefully when more data comes in to
-				 * fill it up we will be able to slide it
-				 * forward. Really I don't think this should
-				 * happen :-0
-				 */
-				;
-			} else {
-				int ii;
-
-				for (ii = 0; ii < nr_distance; ii++) {
+			if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
+				for (ii = 0; ii < distance; ii++) {
 					asoc->nr_mapping_array[ii] =
-					    asoc->nr_mapping_array[nr_slide_from + ii];
+					    asoc->nr_mapping_array[slide_from + ii];
 				}
-				for (ii = nr_distance; ii <= nr_slide_end; ii++) {
+				for (ii = distance; ii <= slide_end; ii++) {
 					asoc->nr_mapping_array[ii] = 0;
 				}
-				asoc->nr_mapping_array_base_tsn += (nr_slide_from << 3);
+				asoc->nr_mapping_array_base_tsn += (slide_from << 3);
 			}
 		}
 	}
@@ -2802,7 +2733,7 @@ sctp_sack_check(struct sctp_tcb *stcb, i
 			 * EY if nr_sacks used then send an nr-sack , a sack
 			 * otherwise
 			 */
-			if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack)
+			if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)
 				sctp_send_nr_sack(stcb);
 			else
 				sctp_send_sack(stcb);
@@ -3496,9 +3427,13 @@ sctp_handle_segments(struct mbuf *m, int
 						/*
 						 * All chunks NOT UNSENT
 						 * fall through here and are
-						 * marked
+						 * marked (leave PR-SCTP
+						 * ones that are to skip
+						 * alone though)
 						 */
-						tp1->sent = SCTP_DATAGRAM_MARKED;
+						if (tp1->sent != SCTP_FORWARD_TSN_SKIP)
+							tp1->sent = SCTP_DATAGRAM_MARKED;
+
 						if (tp1->rec.data.chunk_was_revoked) {
 							/* deflate the cwnd */
 							tp1->whoTo->cwnd -= tp1->book_size;
@@ -5798,7 +5733,9 @@ sctp_kick_prsctp_reorder_queue(struct sc
 					} else {
 						SCTP_TCB_LOCK_ASSERT(stcb);
 						SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
-						if (nr_tsn > asoc->highest_tsn_inside_nr_map)
+						if (compare_with_wrap(nr_tsn,
+						    asoc->highest_tsn_inside_nr_map,
+						    MAX_TSN))
 							asoc->highest_tsn_inside_nr_map = nr_tsn;
 					}
 
@@ -5901,7 +5838,8 @@ sctp_kick_prsctp_reorder_queue(struct sc
 					} else {
 						SCTP_TCB_LOCK_ASSERT(stcb);
 						SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
-						if (nr_tsn > asoc->highest_tsn_inside_nr_map)
+						if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map,
+						    MAX_TSN))
 							asoc->highest_tsn_inside_nr_map = nr_tsn;
 					}
 
@@ -5963,6 +5901,91 @@ sctp_kick_prsctp_reorder_queue(struct sc
 	}
 }
 
+static void
+sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
+    struct sctp_association *asoc,
+    uint16_t stream, uint16_t seq)
+{
+	struct sctp_tmit_chunk *chk, *at;
+
+	if (!TAILQ_EMPTY(&asoc->reasmqueue)) {
+		/* For each one on here see if we need to toss it */
+		/*
+		 * For now large messages held on the reasmqueue that are
+		 * complete will be tossed too. We could in theory do more
+		 * work to spin through and stop after dumping one msg aka
+		 * seeing the start of a new msg at the head, and call the
+		 * delivery function... to see if it can be delivered... But
+		 * for now we just dump everything on the queue.
+		 */
+		chk = TAILQ_FIRST(&asoc->reasmqueue);
+		while (chk) {
+			at = TAILQ_NEXT(chk, sctp_next);
+			if (chk->rec.data.stream_number != stream) {
+				chk = at;
+				continue;
+			}
+			if (chk->rec.data.stream_seq == seq) {
+				/* It needs to be tossed */
+				TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
+				if (compare_with_wrap(chk->rec.data.TSN_seq,
+				    asoc->tsn_last_delivered, MAX_TSN)) {
+					asoc->tsn_last_delivered =
+					    chk->rec.data.TSN_seq;
+					asoc->str_of_pdapi =
+					    chk->rec.data.stream_number;
+					asoc->ssn_of_pdapi =
+					    chk->rec.data.stream_seq;
+					asoc->fragment_flags =
+					    chk->rec.data.rcv_flags;
+				}
+				asoc->size_on_reasm_queue -= chk->send_size;
+				sctp_ucount_decr(asoc->cnt_on_reasm_queue);
+
+				/* Clear up any stream problem */
+				if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) !=
+				    SCTP_DATA_UNORDERED &&
+				    (compare_with_wrap(chk->rec.data.stream_seq,
+				    asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered,
+				    MAX_SEQ))) {
+					/*
+					 * We must dump forward this streams
+					 * sequence number if the chunk is
+					 * not unordered that is being
+					 * skipped. There is a chance that
+					 * if the peer does not include the
+					 * last fragment in its FWD-TSN we
+					 * WILL have a problem here since
+					 * you would have a partial chunk in
+					 * queue that may not be
+					 * deliverable. Also if a Partial
+					 * delivery API as started the user
+					 * may get a partial chunk. The next
+					 * read returning a new chunk...
+					 * really ugly but I see no way
+					 * around it! Maybe a notify??
+					 */
+					asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered =
+					    chk->rec.data.stream_seq;
+				}
+				if (chk->data) {
+					sctp_m_freem(chk->data);
+					chk->data = NULL;
+				}
+				sctp_free_a_chunk(stcb, chk);
+			} else if (compare_with_wrap(chk->rec.data.stream_seq, seq, MAX_SEQ)) {
+				/*
+				 * If the stream_seq is > than the purging
+				 * one, we are done
+				 */
+				break;
+			}
+			chk = at;
+		}
+	}
+}
+
+
 void
 sctp_handle_forward_tsn(struct sctp_tcb *stcb,
     struct sctp_forward_tsn_chunk *fwd, int *abort_flag, struct mbuf *m, int offset)
@@ -5992,13 +6015,14 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 	 */
 	struct sctp_association *asoc;
 	uint32_t new_cum_tsn, gap;
-	unsigned int i, cnt_gone, fwd_sz, cumack_set_flag, m_size;
+	unsigned int i, fwd_sz, cumack_set_flag, m_size;
+	uint32_t str_seq;
 	struct sctp_stream_in *strm;
 	struct sctp_tmit_chunk *chk, *at;
+	struct sctp_queued_to_read *ctl, *sv;
 
 	cumack_set_flag = 0;
 	asoc = &stcb->asoc;
-	cnt_gone = 0;
 	if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
 		SCTPDBG(SCTP_DEBUG_INDATA1,
 		    "Bad size too small/big fwd-tsn\n");
@@ -6102,6 +6126,14 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 		SCTP_TCB_LOCK_ASSERT(stcb);
 		for (i = 0; i <= gap; i++) {
 			SCTP_SET_TSN_PRESENT(asoc->mapping_array, i);
+			/*
+			 * EY if drain is off then every gap-ack is an
+			 * nr-gap-ack
+			 */
+			if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack
+			    && SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
+				SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
+			}
 		}
 		/*
 		 * Now after marking all, slide thing forward but no sack
@@ -6152,7 +6184,6 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 				}
 				asoc->size_on_reasm_queue -= chk->send_size;
 				sctp_ucount_decr(asoc->cnt_on_reasm_queue);
-				cnt_gone++;
 
 				/* Clear up any stream problem */
 				if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) !=
@@ -6188,45 +6219,17 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 			} else {
 				/*
 				 * Ok we have gone beyond the end of the
-				 * fwd-tsn's mark. Some checks...
+				 * fwd-tsn's mark.
 				 */
-				if ((asoc->fragmented_delivery_inprogress) &&
-				    (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) {
-					uint32_t str_seq;
-
-					/*
-					 * Special case PD-API is up and
-					 * what we fwd-tsn' over includes
-					 * one that had the LAST_FRAG. We no
-					 * longer need to do the PD-API.
-					 */
-					asoc->fragmented_delivery_inprogress = 0;
-
-					str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi;
-					sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
-					    stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq, SCTP_SO_NOT_LOCKED);
-
-				}
 				break;
 			}
 			chk = at;
 		}
 	}
-	if (asoc->fragmented_delivery_inprogress) {
-		/*
-		 * Ok we removed cnt_gone chunks in the PD-API queue that
-		 * were being delivered. So now we must turn off the flag.
-		 */
-		uint32_t str_seq;
-
-		str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi;
-		sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
-		    stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq, SCTP_SO_NOT_LOCKED);
-		asoc->fragmented_delivery_inprogress = 0;
-	}
-	/*************************************************************/
-	/* 3. Update the PR-stream re-ordering queues                */
-	/*************************************************************/
+	/*******************************************************/
+	/* 3. Update the PR-stream re-ordering queues and fix  */
+	/* delivery issues as needed.                       */
+	/*******************************************************/
 	fwd_sz -= sizeof(*fwd);
 	if (m && fwd_sz) {
 		/* New method. */
@@ -6235,6 +6238,7 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 
 		offset += sizeof(*fwd);
 
+		SCTP_INP_READ_LOCK(stcb->sctp_ep);
 		num_str = fwd_sz / sizeof(struct sctp_strseq);
 		for (i = 0; i < num_str; i++) {
 			uint16_t st;
@@ -6251,11 +6255,49 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 			stseq->stream = st;
 			st = ntohs(stseq->sequence);
 			stseq->sequence = st;
+
 			/* now process */
+
+			/*
+			 * Ok we now look for the stream/seq on the read
+			 * queue where its not all delivered. If we find it
+			 * we transmute the read entry into a PDI_ABORTED.
+			 */
 			if (stseq->stream >= asoc->streamincnt) {
 				/* screwed up streams, stop!  */
 				break;
 			}
+			if ((asoc->str_of_pdapi == stseq->stream) &&
+			    (asoc->ssn_of_pdapi == stseq->sequence)) {
+				/*
+				 * If this is the one we were partially
+				 * delivering now then we no longer are.
+				 * Note this will change with the reassembly
+				 * re-write.
+				 */
+				asoc->fragmented_delivery_inprogress = 0;
+			}
+			sctp_flush_reassm_for_str_seq(stcb, asoc, stseq->stream, stseq->sequence);
+			TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
+				if ((ctl->sinfo_stream == stseq->stream) &&
+				    (ctl->sinfo_ssn == stseq->sequence)) {
+					str_seq = (stseq->stream << 16) | stseq->sequence;
+					ctl->end_added = 1;
+					ctl->pdapi_aborted = 1;
+					sv = stcb->asoc.control_pdapi;
+					stcb->asoc.control_pdapi = ctl;
+					sctp_notify_partial_delivery_indication(stcb,
+					    SCTP_PARTIAL_DELIVERY_ABORTED,
+					    SCTP_HOLDS_LOCK,
+					    str_seq);
+					stcb->asoc.control_pdapi = sv;
+					break;
+				} else if ((ctl->sinfo_stream == stseq->stream) &&
+				    (compare_with_wrap(ctl->sinfo_ssn, stseq->sequence, MAX_SEQ))) {
+					/* We are past our victim SSN */
+					break;
+				}
+			}
 			strm = &asoc->strmin[stseq->stream];
 			if (compare_with_wrap(stseq->sequence,
 			    strm->last_sequence_delivered, MAX_SEQ)) {
@@ -6267,6 +6309,7 @@ sctp_handle_forward_tsn(struct sctp_tcb 
 			/* sa_ignore NO_NULL_CHK */
 			sctp_kick_prsctp_reorder_queue(stcb, strm);
 		}
+		SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
 	}
 	if (TAILQ_FIRST(&asoc->reasmqueue)) {
 		/* now lets kick out and check for more fragmented delivery */
@@ -7067,7 +7110,8 @@ sctp_handle_nr_sack_segments(struct mbuf
 						 * fall through here and are
 						 * marked
 						 */
-						tp1->sent = SCTP_DATAGRAM_MARKED;
+						if (tp1->sent != SCTP_FORWARD_TSN_SKIP)
+							tp1->sent = SCTP_DATAGRAM_NR_MARKED;
 						if (tp1->rec.data.chunk_was_revoked) {
 							/* deflate the cwnd */
 							tp1->whoTo->cwnd -= tp1->book_size;
@@ -7079,7 +7123,8 @@ sctp_handle_nr_sack_segments(struct mbuf
 						 * nr_marked
 						 */
 						if (all_bit) {
-							tp1->sent = SCTP_DATAGRAM_NR_MARKED;
+							if (tp1->sent != SCTP_FORWARD_TSN_SKIP)
+								tp1->sent = SCTP_DATAGRAM_NR_MARKED;
 							/*
 							 * TAILQ_REMOVE(&asoc
 							 * ->sent_queue,
@@ -7198,7 +7243,8 @@ sctp_handle_nr_sack_segments(struct mbuf
 				while (tp1) {
 					if (tp1->rec.data.TSN_seq == j) {
 						if (tp1->sent != SCTP_DATAGRAM_UNSENT) {
-							tp1->sent = SCTP_DATAGRAM_NR_MARKED;
+							if (tp1->sent != SCTP_FORWARD_TSN_SKIP)
+								tp1->sent = SCTP_DATAGRAM_NR_MARKED;
 							/*
 							 * TAILQ_REMOVE(&asoc
 							 * ->sent_queue,

Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c	Sat Apr  4 11:23:00 2009	(r190688)
+++ head/sys/netinet/sctp_input.c	Sat Apr  4 11:43:32 2009	(r190689)
@@ -3150,8 +3150,10 @@ process_chunk_drop(struct sctp_tcb *stcb
 					    (uintptr_t) stcb,
 					    tp1->rec.data.TSN_seq);
 				}
-				sctp_flight_size_decrease(tp1);
-				sctp_total_flight_decrease(stcb, tp1);
+				if (tp1->sent < SCTP_DATAGRAM_RESEND) {
+					sctp_flight_size_decrease(tp1);
+					sctp_total_flight_decrease(stcb, tp1);
+				}
 			} {
 				/* audit code */
 				unsigned int audit;
@@ -5606,11 +5608,14 @@ sctp_common_input_processing(struct mbuf
 			/* there was a gap before this data was processed */
 			was_a_gap = 1;
 		}
+		stcb->asoc.send_sack = 1;
 		sctp_sack_check(stcb, 1, was_a_gap, &abort_flag);
 		if (abort_flag) {
 			/* Again, we aborted so NO UNLOCK needed */
 			goto out_now;
 		}
+	} else if (fwd_tsn_seen) {
+		stcb->asoc.send_sack = 1;
 	}
 	/* trigger send of any chunks in queue... */
 trigger_send:

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c	Sat Apr  4 11:23:00 2009	(r190688)
+++ head/sys/netinet/sctp_output.c	Sat Apr  4 11:43:32 2009	(r190689)
@@ -1859,1812 +1859,6 @@ struct sack_track sack_array[256] = {
 	}
 };
 
-/* EY  below are nr_sacks version of the preceeding two data structures, identical except their names */
-#define SCTP_MAX_NR_GAPS_INARRAY 4
-struct nr_sack_track {
-	uint8_t right_edge;	/* mergable on the right edge */
-	uint8_t left_edge;	/* mergable on the left edge */
-	uint8_t num_entries;
-	uint8_t spare;
-	struct sctp_nr_gap_ack_block nr_gaps[SCTP_MAX_NR_GAPS_INARRAY];
-};
-
-struct nr_sack_track nr_sack_array[256] = {
-	{0, 0, 0, 0,		/* 0x00 */
-		{{0, 0},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 1, 0,		/* 0x01 */
-		{{0, 0},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x02 */
-		{{1, 1},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 1, 0,		/* 0x03 */
-		{{0, 1},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x04 */
-		{{2, 2},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x05 */
-		{{0, 0},
-		{2, 2},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x06 */
-		{{1, 2},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 1, 0,		/* 0x07 */
-		{{0, 2},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x08 */
-		{{3, 3},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x09 */
-		{{0, 0},
-		{3, 3},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x0a */
-		{{1, 1},
-		{3, 3},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x0b */
-		{{0, 1},
-		{3, 3},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x0c */
-		{{2, 3},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x0d */
-		{{0, 0},
-		{2, 3},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x0e */
-		{{1, 3},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 1, 0,		/* 0x0f */
-		{{0, 3},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x10 */
-		{{4, 4},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x11 */
-		{{0, 0},
-		{4, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x12 */
-		{{1, 1},
-		{4, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x13 */
-		{{0, 1},
-		{4, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x14 */
-		{{2, 2},
-		{4, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 3, 0,		/* 0x15 */
-		{{0, 0},
-		{2, 2},
-		{4, 4},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x16 */
-		{{1, 2},
-		{4, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x17 */
-		{{0, 2},
-		{4, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x18 */
-		{{3, 4},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x19 */
-		{{0, 0},
-		{3, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x1a */
-		{{1, 1},
-		{3, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x1b */
-		{{0, 1},
-		{3, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x1c */
-		{{2, 4},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x1d */
-		{{0, 0},
-		{2, 4},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x1e */
-		{{1, 4},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 1, 0,		/* 0x1f */
-		{{0, 4},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x20 */
-		{{5, 5},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x21 */
-		{{0, 0},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x22 */
-		{{1, 1},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x23 */
-		{{0, 1},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x24 */
-		{{2, 2},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 3, 0,		/* 0x25 */
-		{{0, 0},
-		{2, 2},
-		{5, 5},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x26 */
-		{{1, 2},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x27 */
-		{{0, 2},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x28 */
-		{{3, 3},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 3, 0,		/* 0x29 */
-		{{0, 0},
-		{3, 3},
-		{5, 5},
-		{0, 0}
-		}
-	},
-	{0, 0, 3, 0,		/* 0x2a */
-		{{1, 1},
-		{3, 3},
-		{5, 5},
-		{0, 0}
-		}
-	},
-	{1, 0, 3, 0,		/* 0x2b */
-		{{0, 1},
-		{3, 3},
-		{5, 5},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x2c */
-		{{2, 3},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 3, 0,		/* 0x2d */
-		{{0, 0},
-		{2, 3},
-		{5, 5},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x2e */
-		{{1, 3},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x2f */
-		{{0, 3},
-		{5, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x30 */
-		{{4, 5},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x31 */
-		{{0, 0},
-		{4, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x32 */
-		{{1, 1},
-		{4, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x33 */
-		{{0, 1},
-		{4, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x34 */
-		{{2, 2},
-		{4, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 3, 0,		/* 0x35 */
-		{{0, 0},
-		{2, 2},
-		{4, 5},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x36 */
-		{{1, 2},
-		{4, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x37 */
-		{{0, 2},
-		{4, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x38 */
-		{{3, 5},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x39 */
-		{{0, 0},
-		{3, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 2, 0,		/* 0x3a */
-		{{1, 1},
-		{3, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x3b */
-		{{0, 1},
-		{3, 5},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{0, 0, 1, 0,		/* 0x3c */
-		{{2, 5},
-		{0, 0},
-		{0, 0},
-		{0, 0}
-		}
-	},
-	{1, 0, 2, 0,		/* 0x3d */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list