void sctp_transport_lower_cwnd(struct sctp_transport *transport,
			       sctp_lower_cwnd_t reason)
{
	struct sctp_association *asoc = transport->asoc;

	switch (reason) {
	case SCTP_LOWER_CWND_T3_RTX:
		/* RFC 2960 Section 7.2.3, sctpimpguide
		 * When the T3-rtx timer expires on an address, SCTP should
		 * perform slow start by:
		 *      ssthresh = max(cwnd/2, 4*MTU)
		 *      cwnd = 1*MTU
		 *      partial_bytes_acked = 0
		 */
		transport->ssthresh = max(transport->cwnd/2,
					  4*asoc->pathmtu);
		transport->cwnd = asoc->pathmtu;

		/* T3-rtx also clears fast recovery */
		asoc->fast_recovery = 0;
		break;

	case SCTP_LOWER_CWND_FAST_RTX:
		/* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the
		 * destination address(es) to which the missing DATA chunks
		 * were last sent, according to the formula described in
		 * Section 7.2.3.
		 *
		 * RFC 2960 7.2.3, sctpimpguide Upon detection of packet
		 * losses from SACK (see Section 7.2.4), An endpoint
		 * should do the following:
		 *      ssthresh = max(cwnd/2, 4*MTU)
		 *      cwnd = ssthresh
		 *      partial_bytes_acked = 0
		 */
		if (asoc->fast_recovery)
			return;

		/* Mark Fast recovery */
		asoc->fast_recovery = 1;
		asoc->fast_recovery_exit = asoc->next_tsn - 1;

		transport->ssthresh = max(transport->cwnd/2,
					  4*asoc->pathmtu);
		transport->cwnd = transport->ssthresh;
		break;

	case SCTP_LOWER_CWND_ECNE:
		/* RFC 2481 Section 6.1.2.
		 * If the sender receives an ECN-Echo ACK packet
		 * then the sender knows that congestion was encountered in the
		 * network on the path from the sender to the receiver. The
		 * indication of congestion should be treated just as a
		 * congestion loss in non-ECN Capable TCP. That is, the TCP
		 * source halves the congestion window "cwnd" and reduces the
		 * slow start threshold "ssthresh".
		 * A critical condition is that TCP does not react to
		 * congestion indications more than once every window of
		 * data (or more loosely more than once every round-trip time).
		 */
		if (time_after(jiffies, transport->last_time_ecne_reduced +
					transport->rtt)) {
			transport->ssthresh = max(transport->cwnd/2,
						  4*asoc->pathmtu);
			transport->cwnd = transport->ssthresh;
			transport->last_time_ecne_reduced = jiffies;
		}
		break;

	case SCTP_LOWER_CWND_INACTIVE:
		/* RFC 2960 Section 7.2.1, sctpimpguide
		 * When the endpoint does not transmit data on a given
		 * transport address, the cwnd of the transport address
		 * should be adjusted to max(cwnd/2, 4*MTU) per RTO.
		 * NOTE: Although the draft recommends that this check needs
		 * to be done every RTO interval, we do it every hearbeat
		 * interval.
		 */
		transport->cwnd = max(transport->cwnd/2,
					 4*asoc->pathmtu);
		break;
	}

	transport->partial_bytes_acked = 0;
	SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: "
			  "%d ssthresh: %d\n", __func__,
			  transport, reason,
			  transport->cwnd, transport->ssthresh);
}
void sctp_transport_lower_cwnd(struct sctp_transport *transport,
			       sctp_lower_cwnd_t reason)
{
	struct sctp_association *asoc = transport->asoc;

	switch (reason) {
	case SCTP_LOWER_CWND_T3_RTX:
		 
		transport->ssthresh = max(transport->cwnd/2,
					  4*asoc->pathmtu);
		transport->cwnd = asoc->pathmtu;

		 
		asoc->fast_recovery = 0;
		break;

	case SCTP_LOWER_CWND_FAST_RTX:
		 
		if (asoc->fast_recovery)
			return;

		 
		asoc->fast_recovery = 1;
		asoc->fast_recovery_exit = asoc->next_tsn - 1;

		transport->ssthresh = max(transport->cwnd/2,
					  4*asoc->pathmtu);
		transport->cwnd = transport->ssthresh;
		break;

	case SCTP_LOWER_CWND_ECNE:
		 
		if (time_after(jiffies, transport->last_time_ecne_reduced +
					transport->rtt)) {
			transport->ssthresh = max(transport->cwnd/2,
						  4*asoc->pathmtu);
			transport->cwnd = transport->ssthresh;
			transport->last_time_ecne_reduced = jiffies;
		}
		break;

	case SCTP_LOWER_CWND_INACTIVE:
		 
		transport->cwnd = max(transport->cwnd/2,
					 4*asoc->pathmtu);
		break;
	}

	transport->partial_bytes_acked = 0;
	SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: "
			  "%d ssthresh: %d\n", __func__,
			  transport, reason,
			  transport->cwnd, transport->ssthresh);
}