[SCTP]: Fix 'fast retransmit' to send a TSN only once.

SCTP used to "fast retransmit" a TSN every time we hit the number
of missing reports for the TSN.  However the Implementers Guide
specifies that we should only "fast retransmit" a given TSN once.
Subsequent retransmits should be timeouts only. Also change the
number of missing reports to 3 as per the latest IG(similar to TCP).

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 8c522ae..072f407 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -700,7 +700,7 @@
 	__u8 ecn_ce_done;	/* Have we processed the ECN CE bit? */
 	__u8 pdiscard;		/* Discard the whole packet now? */
 	__u8 tsn_gap_acked;	/* Is this chunk acked by a GAP ACK? */
-	__u8 fast_retransmit;	 /* Is this chunk fast retransmitted? */
+	__s8 fast_retransmit;	 /* Is this chunk fast retransmitted? */
 	__u8 tsn_missing_report; /* Data chunk missing counter. */
 };
 
diff --git a/net/sctp/output.c b/net/sctp/output.c
index a40991e..437cba7 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -608,7 +608,7 @@
 	 *    When a Fast Retransmit is being performed the sender SHOULD
 	 *    ignore the value of cwnd and SHOULD NOT delay retransmission.
 	 */
-	if (!chunk->fast_retransmit)
+	if (chunk->fast_retransmit <= 0)
 		if (transport->flight_size >= transport->cwnd) {
 			retval = SCTP_XMIT_RWND_FULL;
 			goto finish;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index efb72fa..f148f95 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -406,7 +406,7 @@
 		 * chunks that are not yet acked should be added to the
 		 * retransmit queue.
 		 */
-		if ((fast_retransmit && chunk->fast_retransmit) ||
+		if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
 		   (!fast_retransmit && !chunk->tsn_gap_acked)) {
 			/* RFC 2960 6.2.1 Processing a Received SACK
 			 *
@@ -603,7 +603,8 @@
 			/* Mark the chunk as ineligible for fast retransmit 
 			 * after it is retransmitted.
 			 */
-			chunk->fast_retransmit = 0;
+			if (chunk->fast_retransmit > 0)
+				chunk->fast_retransmit = -1;
 
 			*start_timer = 1;
 			q->empty = 0;
@@ -621,7 +622,8 @@
 			list_for_each(lchunk1, lqueue) {
 				chunk1 = list_entry(lchunk1, struct sctp_chunk,
 						    transmitted_list);
-				chunk1->fast_retransmit = 0;
+				if (chunk1->fast_retransmit > 0)
+					chunk1->fast_retransmit = -1;
 			}
 		}
 	}
@@ -1562,11 +1564,11 @@
 		/*
 		 * M4) If any DATA chunk is found to have a
 		 * 'TSN.Missing.Report'
-		 * value larger than or equal to 4, mark that chunk for
+		 * value larger than or equal to 3, mark that chunk for
 		 * retransmission and start the fast retransmit procedure.
 		 */
 
-		if (chunk->tsn_missing_report >= 4) {
+		if (chunk->tsn_missing_report >= 3) {
 			chunk->fast_retransmit = 1;
 			do_fast_retransmit = 1;
 		}