sctp_cc_functions.c revision 310218
1171440Srrs/*-
2171440Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5171440Srrs *
6171440Srrs * Redistribution and use in source and binary forms, with or without
7171440Srrs * modification, are permitted provided that the following conditions are met:
8171440Srrs *
9171440Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11171440Srrs *
12171440Srrs * b) Redistributions in binary form must reproduce the above copyright
13171440Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15171440Srrs *
16171440Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17171440Srrs *    contributors may be used to endorse or promote products derived
18171440Srrs *    from this software without specific prior written permission.
19171440Srrs *
20171440Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21171440Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22171440Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23171440Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24171440Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25171440Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26171440Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27171440Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28171440Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29171440Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30171440Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31171440Srrs */
32171440Srrs
33235828Stuexen#include <sys/cdefs.h>
34235828Stuexen__FBSDID("$FreeBSD: stable/11/sys/netinet/sctp_cc_functions.c 310218 2016-12-18 13:00:11Z tuexen $");
35235828Stuexen
36171440Srrs#include <netinet/sctp_os.h>
37171440Srrs#include <netinet/sctp_var.h>
38171440Srrs#include <netinet/sctp_sysctl.h>
39171440Srrs#include <netinet/sctp_pcb.h>
40171440Srrs#include <netinet/sctp_header.h>
41171440Srrs#include <netinet/sctputil.h>
42171440Srrs#include <netinet/sctp_output.h>
43171440Srrs#include <netinet/sctp_input.h>
44171440Srrs#include <netinet/sctp_indata.h>
45171440Srrs#include <netinet/sctp_uio.h>
46171440Srrs#include <netinet/sctp_timer.h>
47171440Srrs#include <netinet/sctp_auth.h>
48171440Srrs#include <netinet/sctp_asconf.h>
49215817Srrs#include <netinet/sctp_dtrace_declare.h>
50212800Stuexen
51221460Stuexen#define SHIFT_MPTCP_MULTI_N 40
52221460Stuexen#define SHIFT_MPTCP_MULTI_Z 16
53221460Stuexen#define SHIFT_MPTCP_MULTI 8
54221460Stuexen
55217611Stuexenstatic void
56279859Stuexensctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net)
57279859Stuexen{
58279859Stuexen	if ((assoc->max_cwnd > 0) &&
59279859Stuexen	    (net->cwnd > assoc->max_cwnd) &&
60279859Stuexen	    (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
61279859Stuexen		net->cwnd = assoc->max_cwnd;
62279859Stuexen		if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
63279859Stuexen			net->cwnd = net->mtu - sizeof(struct sctphdr);
64279859Stuexen		}
65279859Stuexen	}
66279859Stuexen}
67279859Stuexen
68279859Stuexenstatic void
69171440Srrssctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
70171440Srrs{
71212800Stuexen	struct sctp_association *assoc;
72212800Stuexen	uint32_t cwnd_in_mtu;
73212800Stuexen
74212800Stuexen	assoc = &stcb->asoc;
75212800Stuexen	cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
76216672Stuexen	if (cwnd_in_mtu == 0) {
77216672Stuexen		/* Using 0 means that the value of RFC 4960 is used. */
78216672Stuexen		net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
79216672Stuexen	} else {
80216672Stuexen		/*
81216672Stuexen		 * We take the minimum of the burst limit and the initial
82216672Stuexen		 * congestion window.
83216672Stuexen		 */
84216672Stuexen		if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst))
85216672Stuexen			cwnd_in_mtu = assoc->max_burst;
86216672Stuexen		net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
87216672Stuexen	}
88221460Stuexen	if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
89221460Stuexen	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) {
90217469Stuexen		/* In case of resource pooling initialize appropriately */
91217469Stuexen		net->cwnd /= assoc->numnets;
92217469Stuexen		if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
93217469Stuexen			net->cwnd = net->mtu - sizeof(struct sctphdr);
94217469Stuexen		}
95217469Stuexen	}
96279859Stuexen	sctp_enforce_cwnd_limit(assoc, net);
97212800Stuexen	net->ssthresh = assoc->peers_rwnd;
98292384Smarkj	SDT_PROBE5(sctp, cwnd, net, init,
99215817Srrs	    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
100215817Srrs	    0, net->cwnd);
101212800Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) &
102212800Stuexen	    (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
103171440Srrs		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
104171440Srrs	}
105171440Srrs}
106171440Srrs
107217611Stuexenstatic void
108171440Srrssctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
109171440Srrs    struct sctp_association *asoc)
110171440Srrs{
111171440Srrs	struct sctp_nets *net;
112217469Stuexen	uint32_t t_ssthresh, t_cwnd;
113221460Stuexen	uint64_t t_ucwnd_sbw;
114171440Srrs
115217469Stuexen	/* MT FIXME: Don't compute this over and over again */
116217469Stuexen	t_ssthresh = 0;
117217469Stuexen	t_cwnd = 0;
118221460Stuexen	t_ucwnd_sbw = 0;
119221460Stuexen	if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) ||
120221460Stuexen	    (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) {
121217469Stuexen		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
122217469Stuexen			t_ssthresh += net->ssthresh;
123217469Stuexen			t_cwnd += net->cwnd;
124221460Stuexen			if (net->lastsa > 0) {
125221460Stuexen				t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) net->lastsa;
126221460Stuexen			}
127217469Stuexen		}
128221460Stuexen		if (t_ucwnd_sbw == 0) {
129221460Stuexen			t_ucwnd_sbw = 1;
130221460Stuexen		}
131217469Stuexen	}
132171440Srrs	/*-
133216669Stuexen	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
134171440Srrs	 * (net->fast_retran_loss_recovery == 0)))
135171440Srrs	 */
136171440Srrs	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
137211944Stuexen		if ((asoc->fast_retran_loss_recovery == 0) ||
138216669Stuexen		    (asoc->sctp_cmt_on_off > 0)) {
139171440Srrs			/* out of a RFC2582 Fast recovery window? */
140171440Srrs			if (net->net_ack > 0) {
141171440Srrs				/*
142171440Srrs				 * per section 7.2.3, are there any
143171440Srrs				 * destinations that had a fast retransmit
144171440Srrs				 * to them. If so what we need to do is
145171440Srrs				 * adjust ssthresh and cwnd.
146171440Srrs				 */
147171440Srrs				struct sctp_tmit_chunk *lchk;
148171440Srrs				int old_cwnd = net->cwnd;
149171440Srrs
150221460Stuexen				if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) ||
151221460Stuexen				    (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) {
152221460Stuexen					if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) {
153221460Stuexen						net->ssthresh = (uint32_t) (((uint64_t) 4 *
154221460Stuexen						    (uint64_t) net->mtu *
155221460Stuexen						    (uint64_t) net->ssthresh) /
156221460Stuexen						    (uint64_t) t_ssthresh);
157221460Stuexen
158221460Stuexen					}
159221460Stuexen					if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) {
160221460Stuexen						uint32_t srtt;
161221460Stuexen
162221460Stuexen						srtt = net->lastsa;
163310218Stuexen						/* lastsa>>3;  we don't need
164310218Stuexen						 * to devide ... */
165221460Stuexen						if (srtt == 0) {
166221460Stuexen							srtt = 1;
167221460Stuexen						}
168310218Stuexen						/* Short Version => Equal to
169310218Stuexen						 * Contel Version MBe */
170221460Stuexen						net->ssthresh = (uint32_t) (((uint64_t) 4 *
171221460Stuexen						    (uint64_t) net->mtu *
172221460Stuexen						    (uint64_t) net->cwnd) /
173221460Stuexen						    ((uint64_t) srtt *
174221460Stuexen						    t_ucwnd_sbw));
175221460Stuexen						 /* INCREASE FACTOR */ ;
176221460Stuexen					}
177217469Stuexen					if ((net->cwnd > t_cwnd / 2) &&
178217469Stuexen					    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
179217469Stuexen						net->ssthresh = net->cwnd - t_cwnd / 2;
180217469Stuexen					}
181217469Stuexen					if (net->ssthresh < net->mtu) {
182217469Stuexen						net->ssthresh = net->mtu;
183217469Stuexen					}
184217469Stuexen				} else {
185217469Stuexen					net->ssthresh = net->cwnd / 2;
186217469Stuexen					if (net->ssthresh < (net->mtu * 2)) {
187217469Stuexen						net->ssthresh = 2 * net->mtu;
188217469Stuexen					}
189171440Srrs				}
190171440Srrs				net->cwnd = net->ssthresh;
191279859Stuexen				sctp_enforce_cwnd_limit(asoc, net);
192292384Smarkj				SDT_PROBE5(sctp, cwnd, net, fr,
193215817Srrs				    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
194215817Srrs				    old_cwnd, net->cwnd);
195179783Srrs				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
196171440Srrs					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
197171440Srrs					    SCTP_CWND_LOG_FROM_FR);
198171440Srrs				}
199171440Srrs				lchk = TAILQ_FIRST(&asoc->send_queue);
200171440Srrs
201171440Srrs				net->partial_bytes_acked = 0;
202171440Srrs				/* Turn on fast recovery window */
203171440Srrs				asoc->fast_retran_loss_recovery = 1;
204171440Srrs				if (lchk == NULL) {
205171440Srrs					/* Mark end of the window */
206171440Srrs					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
207171440Srrs				} else {
208171440Srrs					asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
209171440Srrs				}
210171440Srrs
211171440Srrs				/*
212171440Srrs				 * CMT fast recovery -- per destination
213171440Srrs				 * recovery variable.
214171440Srrs				 */
215171440Srrs				net->fast_retran_loss_recovery = 1;
216171440Srrs
217171440Srrs				if (lchk == NULL) {
218171440Srrs					/* Mark end of the window */
219171440Srrs					net->fast_recovery_tsn = asoc->sending_seq - 1;
220171440Srrs				} else {
221171440Srrs					net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
222171440Srrs				}
223171440Srrs
224171440Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
225283650Stuexen				    stcb->sctp_ep, stcb, net,
226283650Stuexen				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1);
227171440Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
228171440Srrs				    stcb->sctp_ep, stcb, net);
229171440Srrs			}
230171440Srrs		} else if (net->net_ack > 0) {
231171440Srrs			/*
232171440Srrs			 * Mark a peg that we WOULD have done a cwnd
233171440Srrs			 * reduction but RFC2582 prevented this action.
234171440Srrs			 */
235171440Srrs			SCTP_STAT_INCR(sctps_fastretransinrtt);
236171440Srrs		}
237171440Srrs	}
238171440Srrs}
239171440Srrs
240219397Srrs/* Defines for instantaneous bw decisions */
241298942Spfg#define SCTP_INST_LOOSING 1	/* Losing to other flows */
242219397Srrs#define SCTP_INST_NEUTRAL 2	/* Neutral, no indication */
243219397Srrs#define SCTP_INST_GAINING 3	/* Gaining, step down possible */
244219120Srrs
245219397Srrs
246219397Srrsstatic int
247219397Srrscc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw,
248219397Srrs    uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind)
249219397Srrs{
250219397Srrs	uint64_t oth, probepoint;
251219397Srrs
252219397Srrs	probepoint = (((uint64_t) net->cwnd) << 32);
253219397Srrs	if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
254219397Srrs		/*
255219397Srrs		 * rtt increased we don't update bw.. so we don't update the
256219397Srrs		 * rtt either.
257219397Srrs		 */
258219397Srrs		/* Probe point 5 */
259219397Srrs		probepoint |= ((5 << 16) | 1);
260292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttvar,
261219397Srrs		    vtag,
262219397Srrs		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
263219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
264219397Srrs		    net->flight_size,
265219397Srrs		    probepoint);
266219397Srrs		if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) {
267219397Srrs			if (net->cc_mod.rtcc.last_step_state == 5)
268219397Srrs				net->cc_mod.rtcc.step_cnt++;
269219397Srrs			else
270219397Srrs				net->cc_mod.rtcc.step_cnt = 1;
271219397Srrs			net->cc_mod.rtcc.last_step_state = 5;
272219397Srrs			if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) ||
273219397Srrs			    ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
274219397Srrs			    ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
275219397Srrs				/* Try a step down */
276219397Srrs				oth = net->cc_mod.rtcc.vol_reduce;
277219397Srrs				oth <<= 16;
278219397Srrs				oth |= net->cc_mod.rtcc.step_cnt;
279219397Srrs				oth <<= 16;
280219397Srrs				oth |= net->cc_mod.rtcc.last_step_state;
281292384Smarkj				SDT_PROBE5(sctp, cwnd, net, rttstep,
282219397Srrs				    vtag,
283219397Srrs				    ((net->cc_mod.rtcc.lbw << 32) | nbw),
284219397Srrs				    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
285219397Srrs				    oth,
286219397Srrs				    probepoint);
287219397Srrs				if (net->cwnd > (4 * net->mtu)) {
288219397Srrs					net->cwnd -= net->mtu;
289219397Srrs					net->cc_mod.rtcc.vol_reduce++;
290219397Srrs				} else {
291219397Srrs					net->cc_mod.rtcc.step_cnt = 0;
292219397Srrs				}
293219397Srrs			}
294219397Srrs		}
295219397Srrs		return (1);
296219397Srrs	}
297219397Srrs	if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
298219397Srrs		/*
299219397Srrs		 * rtt decreased, there could be more room. we update both
300219397Srrs		 * the bw and the rtt here to lock this in as a good step
301219397Srrs		 * down.
302219397Srrs		 */
303219397Srrs		/* Probe point 6 */
304219397Srrs		probepoint |= ((6 << 16) | 0);
305292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttvar,
306219397Srrs		    vtag,
307219397Srrs		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
308219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
309219397Srrs		    net->flight_size,
310219397Srrs		    probepoint);
311219397Srrs		if (net->cc_mod.rtcc.steady_step) {
312219397Srrs			oth = net->cc_mod.rtcc.vol_reduce;
313219397Srrs			oth <<= 16;
314219397Srrs			oth |= net->cc_mod.rtcc.step_cnt;
315219397Srrs			oth <<= 16;
316219397Srrs			oth |= net->cc_mod.rtcc.last_step_state;
317292384Smarkj			SDT_PROBE5(sctp, cwnd, net, rttstep,
318219397Srrs			    vtag,
319219397Srrs			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
320219397Srrs			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
321219397Srrs			    oth,
322219397Srrs			    probepoint);
323219397Srrs			if ((net->cc_mod.rtcc.last_step_state == 5) &&
324219397Srrs			    (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) {
325219397Srrs				/* Step down worked */
326219397Srrs				net->cc_mod.rtcc.step_cnt = 0;
327219397Srrs				return (1);
328219397Srrs			} else {
329219397Srrs				net->cc_mod.rtcc.last_step_state = 6;
330219397Srrs				net->cc_mod.rtcc.step_cnt = 0;
331219397Srrs			}
332219397Srrs		}
333219397Srrs		net->cc_mod.rtcc.lbw = nbw;
334219397Srrs		net->cc_mod.rtcc.lbw_rtt = net->rtt;
335219397Srrs		net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
336219397Srrs		if (inst_ind == SCTP_INST_GAINING)
337219397Srrs			return (1);
338219397Srrs		else if (inst_ind == SCTP_INST_NEUTRAL)
339219397Srrs			return (1);
340219397Srrs		else
341219397Srrs			return (0);
342219397Srrs	}
343219397Srrs	/*
344219397Srrs	 * Ok bw and rtt remained the same .. no update to any
345219397Srrs	 */
346219397Srrs	/* Probe point 7 */
347219397Srrs	probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq);
348292384Smarkj	SDT_PROBE5(sctp, cwnd, net, rttvar,
349219397Srrs	    vtag,
350219397Srrs	    ((net->cc_mod.rtcc.lbw << 32) | nbw),
351219397Srrs	    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
352219397Srrs	    net->flight_size,
353219397Srrs	    probepoint);
354219397Srrs	if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) {
355219397Srrs		if (net->cc_mod.rtcc.last_step_state == 5)
356219397Srrs			net->cc_mod.rtcc.step_cnt++;
357219397Srrs		else
358219397Srrs			net->cc_mod.rtcc.step_cnt = 1;
359219397Srrs		net->cc_mod.rtcc.last_step_state = 5;
360219397Srrs		if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) ||
361219397Srrs		    ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
362219397Srrs		    ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
363219397Srrs			/* Try a step down */
364219397Srrs			if (net->cwnd > (4 * net->mtu)) {
365219397Srrs				net->cwnd -= net->mtu;
366219397Srrs				net->cc_mod.rtcc.vol_reduce++;
367219397Srrs				return (1);
368219397Srrs			} else {
369219397Srrs				net->cc_mod.rtcc.step_cnt = 0;
370219397Srrs			}
371219397Srrs		}
372219397Srrs	}
373219397Srrs	if (inst_ind == SCTP_INST_GAINING)
374219397Srrs		return (1);
375219397Srrs	else if (inst_ind == SCTP_INST_NEUTRAL)
376219397Srrs		return (1);
377219397Srrs	else
378219397Srrs		return ((int)net->cc_mod.rtcc.ret_from_eq);
379219397Srrs}
380219397Srrs
381219397Srrsstatic int
382219397Srrscc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset,
383219397Srrs    uint64_t vtag, uint8_t inst_ind)
384219397Srrs{
385219397Srrs	uint64_t oth, probepoint;
386219397Srrs
387219397Srrs	/* Bandwidth decreased. */
388219397Srrs	probepoint = (((uint64_t) net->cwnd) << 32);
389219397Srrs	if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
390219397Srrs		/* rtt increased */
391219397Srrs		/* Did we add more */
392219397Srrs		if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) &&
393219397Srrs		    (inst_ind != SCTP_INST_LOOSING)) {
394219397Srrs			/* We caused it maybe.. back off? */
395219397Srrs			/* PROBE POINT 1 */
396219397Srrs			probepoint |= ((1 << 16) | 1);
397292384Smarkj			SDT_PROBE5(sctp, cwnd, net, rttvar,
398219397Srrs			    vtag,
399219397Srrs			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
400219397Srrs			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
401219397Srrs			    net->flight_size,
402219397Srrs			    probepoint);
403219397Srrs			if (net->cc_mod.rtcc.ret_from_eq) {
404310218Stuexen				/* Switch over to CA if we are less
405310218Stuexen				 * aggressive */
406219397Srrs				net->ssthresh = net->cwnd - 1;
407219397Srrs				net->partial_bytes_acked = 0;
408219397Srrs			}
409219397Srrs			return (1);
410219397Srrs		}
411219397Srrs		/* Probe point 2 */
412219397Srrs		probepoint |= ((2 << 16) | 0);
413292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttvar,
414219397Srrs		    vtag,
415219397Srrs		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
416219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
417219397Srrs		    net->flight_size,
418219397Srrs		    probepoint);
419219397Srrs		/* Someone else - fight for more? */
420219397Srrs		if (net->cc_mod.rtcc.steady_step) {
421219397Srrs			oth = net->cc_mod.rtcc.vol_reduce;
422219397Srrs			oth <<= 16;
423219397Srrs			oth |= net->cc_mod.rtcc.step_cnt;
424219397Srrs			oth <<= 16;
425219397Srrs			oth |= net->cc_mod.rtcc.last_step_state;
426292384Smarkj			SDT_PROBE5(sctp, cwnd, net, rttstep,
427219397Srrs			    vtag,
428219397Srrs			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
429219397Srrs			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
430219397Srrs			    oth,
431219397Srrs			    probepoint);
432219397Srrs			/*
433219397Srrs			 * Did we voluntarily give up some? if so take one
434219397Srrs			 * back please
435219397Srrs			 */
436219397Srrs			if ((net->cc_mod.rtcc.vol_reduce) &&
437219397Srrs			    (inst_ind != SCTP_INST_GAINING)) {
438219397Srrs				net->cwnd += net->mtu;
439279859Stuexen				sctp_enforce_cwnd_limit(&stcb->asoc, net);
440219397Srrs				net->cc_mod.rtcc.vol_reduce--;
441219397Srrs			}
442219397Srrs			net->cc_mod.rtcc.last_step_state = 2;
443219397Srrs			net->cc_mod.rtcc.step_cnt = 0;
444219397Srrs		}
445219397Srrs		goto out_decision;
446219397Srrs	} else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
447219397Srrs		/* bw & rtt decreased */
448219397Srrs		/* Probe point 3 */
449219397Srrs		probepoint |= ((3 << 16) | 0);
450292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttvar,
451219397Srrs		    vtag,
452219397Srrs		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
453219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
454219397Srrs		    net->flight_size,
455219397Srrs		    probepoint);
456219397Srrs		if (net->cc_mod.rtcc.steady_step) {
457219397Srrs			oth = net->cc_mod.rtcc.vol_reduce;
458219397Srrs			oth <<= 16;
459219397Srrs			oth |= net->cc_mod.rtcc.step_cnt;
460219397Srrs			oth <<= 16;
461219397Srrs			oth |= net->cc_mod.rtcc.last_step_state;
462292384Smarkj			SDT_PROBE5(sctp, cwnd, net, rttstep,
463219397Srrs			    vtag,
464219397Srrs			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
465219397Srrs			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
466219397Srrs			    oth,
467219397Srrs			    probepoint);
468219397Srrs			if ((net->cc_mod.rtcc.vol_reduce) &&
469219397Srrs			    (inst_ind != SCTP_INST_GAINING)) {
470219397Srrs				net->cwnd += net->mtu;
471279859Stuexen				sctp_enforce_cwnd_limit(&stcb->asoc, net);
472219397Srrs				net->cc_mod.rtcc.vol_reduce--;
473219397Srrs			}
474219397Srrs			net->cc_mod.rtcc.last_step_state = 3;
475219397Srrs			net->cc_mod.rtcc.step_cnt = 0;
476219397Srrs		}
477219397Srrs		goto out_decision;
478219397Srrs	}
479219397Srrs	/* The bw decreased but rtt stayed the same */
480219397Srrs	/* Probe point 4 */
481219397Srrs	probepoint |= ((4 << 16) | 0);
482292384Smarkj	SDT_PROBE5(sctp, cwnd, net, rttvar,
483219397Srrs	    vtag,
484219397Srrs	    ((net->cc_mod.rtcc.lbw << 32) | nbw),
485219397Srrs	    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
486219397Srrs	    net->flight_size,
487219397Srrs	    probepoint);
488219397Srrs	if (net->cc_mod.rtcc.steady_step) {
489219397Srrs		oth = net->cc_mod.rtcc.vol_reduce;
490219397Srrs		oth <<= 16;
491219397Srrs		oth |= net->cc_mod.rtcc.step_cnt;
492219397Srrs		oth <<= 16;
493219397Srrs		oth |= net->cc_mod.rtcc.last_step_state;
494292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttstep,
495219397Srrs		    vtag,
496219397Srrs		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
497219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
498219397Srrs		    oth,
499219397Srrs		    probepoint);
500219397Srrs		if ((net->cc_mod.rtcc.vol_reduce) &&
501219397Srrs		    (inst_ind != SCTP_INST_GAINING)) {
502219397Srrs			net->cwnd += net->mtu;
503279859Stuexen			sctp_enforce_cwnd_limit(&stcb->asoc, net);
504219397Srrs			net->cc_mod.rtcc.vol_reduce--;
505219397Srrs		}
506219397Srrs		net->cc_mod.rtcc.last_step_state = 4;
507219397Srrs		net->cc_mod.rtcc.step_cnt = 0;
508219397Srrs	}
509219397Srrsout_decision:
510219397Srrs	net->cc_mod.rtcc.lbw = nbw;
511219397Srrs	net->cc_mod.rtcc.lbw_rtt = net->rtt;
512219397Srrs	net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
513219397Srrs	if (inst_ind == SCTP_INST_GAINING) {
514219397Srrs		return (1);
515219397Srrs	} else {
516219397Srrs		return (0);
517219397Srrs	}
518219397Srrs}
519219397Srrs
520219397Srrsstatic int
521228653Stuexencc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag)
522219397Srrs{
523219397Srrs	uint64_t oth, probepoint;
524219397Srrs
525219397Srrs	/*
526219397Srrs	 * BW increased, so update and return 0, since all actions in our
527219397Srrs	 * table say to do the normal CC update. Note that we pay no
528219397Srrs	 * attention to the inst_ind since our overall sum is increasing.
529219397Srrs	 */
530219397Srrs	/* PROBE POINT 0 */
531219397Srrs	probepoint = (((uint64_t) net->cwnd) << 32);
532292384Smarkj	SDT_PROBE5(sctp, cwnd, net, rttvar,
533219397Srrs	    vtag,
534219397Srrs	    ((net->cc_mod.rtcc.lbw << 32) | nbw),
535219397Srrs	    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
536219397Srrs	    net->flight_size,
537219397Srrs	    probepoint);
538219397Srrs	if (net->cc_mod.rtcc.steady_step) {
539219397Srrs		oth = net->cc_mod.rtcc.vol_reduce;
540219397Srrs		oth <<= 16;
541219397Srrs		oth |= net->cc_mod.rtcc.step_cnt;
542219397Srrs		oth <<= 16;
543219397Srrs		oth |= net->cc_mod.rtcc.last_step_state;
544292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttstep,
545219397Srrs		    vtag,
546219397Srrs		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
547219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
548219397Srrs		    oth,
549219397Srrs		    probepoint);
550219397Srrs		net->cc_mod.rtcc.last_step_state = 0;
551219397Srrs		net->cc_mod.rtcc.step_cnt = 0;
552219397Srrs		net->cc_mod.rtcc.vol_reduce = 0;
553219397Srrs	}
554219397Srrs	net->cc_mod.rtcc.lbw = nbw;
555219397Srrs	net->cc_mod.rtcc.lbw_rtt = net->rtt;
556219397Srrs	net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
557219397Srrs	return (0);
558219397Srrs}
559219397Srrs
560298942Spfg/* RTCC Algorithm to limit growth of cwnd, return
561219120Srrs * true if you want to NOT allow cwnd growth
562219120Srrs */
563219120Srrsstatic int
564219120Srrscc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
565219120Srrs{
566228907Stuexen	uint64_t bw_offset, rtt_offset;
567228907Stuexen	uint64_t probepoint, rtt, vtag;
568219397Srrs	uint64_t bytes_for_this_rtt, inst_bw;
569219397Srrs	uint64_t div, inst_off;
570219397Srrs	int bw_shift;
571219397Srrs	uint8_t inst_ind;
572219397Srrs	int ret;
573219120Srrs
574219120Srrs	/*-
575219120Srrs	 * Here we need to see if we want
576219120Srrs	 * to limit cwnd growth due to increase
577219120Srrs	 * in overall rtt but no increase in bw.
578219120Srrs	 * We use the following table to figure
579219120Srrs	 * out what we should do. When we return
580219120Srrs	 * 0, cc update goes on as planned. If we
581219120Srrs	 * return 1, then no cc update happens and cwnd
582219120Srrs	 * stays where it is at.
583219120Srrs	 * ----------------------------------
584219120Srrs	 *   BW    |    RTT   | Action
585219120Srrs	 * *********************************
586219120Srrs	 *   INC   |    INC   | return 0
587219120Srrs	 * ----------------------------------
588219120Srrs	 *   INC   |    SAME  | return 0
589219120Srrs	 * ----------------------------------
590219120Srrs	 *   INC   |    DECR  | return 0
591219120Srrs	 * ----------------------------------
592219120Srrs	 *   SAME  |    INC   | return 1
593219120Srrs	 * ----------------------------------
594219120Srrs	 *   SAME  |    SAME  | return 1
595219120Srrs	 * ----------------------------------
596219120Srrs	 *   SAME  |    DECR  | return 0
597219120Srrs	 * ----------------------------------
598219120Srrs	 *   DECR  |    INC   | return 0 or 1 based on if we caused.
599219120Srrs	 * ----------------------------------
600219120Srrs	 *   DECR  |    SAME  | return 0
601219120Srrs	 * ----------------------------------
602219120Srrs	 *   DECR  |    DECR  | return 0
603219120Srrs	 * ----------------------------------
604219120Srrs	 *
605219120Srrs	 * We are a bit fuzz on what an increase or
606219120Srrs	 * decrease is. For BW it is the same if
607219120Srrs	 * it did not change within 1/64th. For
608219120Srrs	 * RTT it stayed the same if it did not
609219120Srrs	 * change within 1/32nd
610219120Srrs	 */
611219397Srrs	bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw);
612219120Srrs	rtt = stcb->asoc.my_vtag;
613219120Srrs	vtag = (rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport);
614219120Srrs	probepoint = (((uint64_t) net->cwnd) << 32);
615219120Srrs	rtt = net->rtt;
616219397Srrs	if (net->cc_mod.rtcc.rtt_set_this_sack) {
617219397Srrs		net->cc_mod.rtcc.rtt_set_this_sack = 0;
618219397Srrs		bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc;
619219397Srrs		net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes;
620219397Srrs		if (net->rtt) {
621219397Srrs			div = net->rtt / 1000;
622219397Srrs			if (div) {
623219397Srrs				inst_bw = bytes_for_this_rtt / div;
624219397Srrs				inst_off = inst_bw >> bw_shift;
625219397Srrs				if (inst_bw > nbw)
626219397Srrs					inst_ind = SCTP_INST_GAINING;
627219397Srrs				else if ((inst_bw + inst_off) < nbw)
628219397Srrs					inst_ind = SCTP_INST_LOOSING;
629219397Srrs				else
630219397Srrs					inst_ind = SCTP_INST_NEUTRAL;
631219397Srrs				probepoint |= ((0xb << 16) | inst_ind);
632219397Srrs			} else {
633228907Stuexen				inst_ind = net->cc_mod.rtcc.last_inst_ind;
634219397Srrs				inst_bw = bytes_for_this_rtt / (uint64_t) (net->rtt);
635219397Srrs				/* Can't determine do not change */
636219397Srrs				probepoint |= ((0xc << 16) | inst_ind);
637219397Srrs			}
638219397Srrs		} else {
639228907Stuexen			inst_ind = net->cc_mod.rtcc.last_inst_ind;
640219397Srrs			inst_bw = bytes_for_this_rtt;
641219397Srrs			/* Can't determine do not change */
642219397Srrs			probepoint |= ((0xd << 16) | inst_ind);
643219397Srrs		}
644292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttvar,
645219120Srrs		    vtag,
646219397Srrs		    ((nbw << 32) | inst_bw),
647219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt),
648219397Srrs		    net->flight_size,
649219120Srrs		    probepoint);
650219397Srrs	} else {
651219397Srrs		/* No rtt measurement, use last one */
652219397Srrs		inst_ind = net->cc_mod.rtcc.last_inst_ind;
653219120Srrs	}
654219397Srrs	bw_offset = net->cc_mod.rtcc.lbw >> bw_shift;
655219397Srrs	if (nbw > net->cc_mod.rtcc.lbw + bw_offset) {
656228653Stuexen		ret = cc_bw_increase(stcb, net, nbw, vtag);
657219397Srrs		goto out;
658219397Srrs	}
659219120Srrs	rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt);
660219120Srrs	if (nbw < net->cc_mod.rtcc.lbw - bw_offset) {
661219397Srrs		ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind);
662219397Srrs		goto out;
663219120Srrs	}
664219120Srrs	/*
665219120Srrs	 * If we reach here then we are in a situation where the bw stayed
666219120Srrs	 * the same.
667219120Srrs	 */
668219397Srrs	ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind);
669219397Srrsout:
670219397Srrs	net->cc_mod.rtcc.last_inst_ind = inst_ind;
671219397Srrs	return (ret);
672219120Srrs}
673219120Srrs
674217611Stuexenstatic void
675219120Srrssctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
676171440Srrs    struct sctp_association *asoc,
677228653Stuexen    int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc)
678171440Srrs{
679171440Srrs	struct sctp_nets *net;
680215817Srrs	int old_cwnd;
681217469Stuexen	uint32_t t_ssthresh, t_cwnd, incr;
682221460Stuexen	uint64_t t_ucwnd_sbw;
683221460Stuexen	uint64_t t_path_mptcp;
684221460Stuexen	uint64_t mptcp_like_alpha;
685221460Stuexen	uint32_t srtt;
686221460Stuexen	uint64_t max_path;
687171440Srrs
688217469Stuexen	/* MT FIXME: Don't compute this over and over again */
689217469Stuexen	t_ssthresh = 0;
690217469Stuexen	t_cwnd = 0;
691221460Stuexen	t_ucwnd_sbw = 0;
692221460Stuexen	t_path_mptcp = 0;
693221460Stuexen	mptcp_like_alpha = 1;
694221460Stuexen	if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
695221460Stuexen	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) ||
696221460Stuexen	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) {
697221460Stuexen		max_path = 0;
698217469Stuexen		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
699217469Stuexen			t_ssthresh += net->ssthresh;
700217469Stuexen			t_cwnd += net->cwnd;
701221460Stuexen			/* lastsa>>3;  we don't need to devide ... */
702221460Stuexen			srtt = net->lastsa;
703221460Stuexen			if (srtt > 0) {
704221460Stuexen				uint64_t tmp;
705221460Stuexen
706221460Stuexen				t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) srtt;
707221460Stuexen				t_path_mptcp += (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_Z) /
708221460Stuexen				    (((uint64_t) net->mtu) * (uint64_t) srtt);
709221460Stuexen				tmp = (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_N) /
710221460Stuexen				    ((uint64_t) net->mtu * (uint64_t) (srtt * srtt));
711221460Stuexen				if (tmp > max_path) {
712221460Stuexen					max_path = tmp;
713221460Stuexen				}
714221460Stuexen			}
715217469Stuexen		}
716221460Stuexen		if (t_path_mptcp > 0) {
717221460Stuexen			mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp);
718221460Stuexen		} else {
719221460Stuexen			mptcp_like_alpha = 1;
720221460Stuexen		}
721217469Stuexen	}
722228907Stuexen	if (t_ssthresh == 0) {
723228907Stuexen		t_ssthresh = 1;
724228907Stuexen	}
725228907Stuexen	if (t_ucwnd_sbw == 0) {
726228907Stuexen		t_ucwnd_sbw = 1;
727228907Stuexen	}
728171440Srrs	/******************************/
729171440Srrs	/* update cwnd and Early FR   */
730171440Srrs	/******************************/
731171440Srrs	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
732171440Srrs
733171440Srrs#ifdef JANA_CMT_FAST_RECOVERY
734171440Srrs		/*
735171440Srrs		 * CMT fast recovery code. Need to debug.
736171440Srrs		 */
737171440Srrs		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
738217469Stuexen			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
739217469Stuexen			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
740171440Srrs				net->will_exit_fast_recovery = 1;
741171440Srrs			}
742171440Srrs		}
743171440Srrs#endif
744171440Srrs		/* if nothing was acked on this destination skip it */
745171440Srrs		if (net->net_ack == 0) {
746179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
747171440Srrs				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
748171440Srrs			}
749171440Srrs			continue;
750171440Srrs		}
751171440Srrs#ifdef JANA_CMT_FAST_RECOVERY
752171440Srrs		/*
753171440Srrs		 * CMT fast recovery code
754171440Srrs		 */
755171440Srrs		/*
756216669Stuexen		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
757216669Stuexen		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
758216669Stuexen		 * } else if (sctp_cmt_on_off == 0 &&
759171440Srrs		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
760171440Srrs		 */
761171440Srrs#endif
762171440Srrs
763211944Stuexen		if (asoc->fast_retran_loss_recovery &&
764211944Stuexen		    (will_exit == 0) &&
765211944Stuexen		    (asoc->sctp_cmt_on_off == 0)) {
766171440Srrs			/*
767171440Srrs			 * If we are in loss recovery we skip any cwnd
768171440Srrs			 * update
769171440Srrs			 */
770224641Stuexen			return;
771171440Srrs		}
772171440Srrs		/*
773219120Srrs		 * Did any measurements go on for this network?
774219120Srrs		 */
775219120Srrs		if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) {
776219120Srrs			uint64_t nbw;
777219120Srrs
778219120Srrs			/*
779219120Srrs			 * At this point our bw_bytes has been updated by
780219120Srrs			 * incoming sack information.
781310218Stuexen			 *
782219120Srrs			 * But our bw may not yet be set.
783310218Stuexen			 *
784219120Srrs			 */
785219120Srrs			if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) {
786219120Srrs				nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000);
787219120Srrs			} else {
788219120Srrs				nbw = net->cc_mod.rtcc.bw_bytes;
789219120Srrs			}
790219120Srrs			if (net->cc_mod.rtcc.lbw) {
791219120Srrs				if (cc_bw_limit(stcb, net, nbw)) {
792219120Srrs					/* Hold here, no update */
793224641Stuexen					continue;
794219120Srrs				}
795219120Srrs			} else {
796219120Srrs				uint64_t vtag, probepoint;
797219120Srrs
798219120Srrs				probepoint = (((uint64_t) net->cwnd) << 32);
799219120Srrs				probepoint |= ((0xa << 16) | 0);
800219120Srrs				vtag = (net->rtt << 32) |
801219120Srrs				    (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
802219120Srrs				    (stcb->rport);
803219120Srrs
804292384Smarkj				SDT_PROBE5(sctp, cwnd, net, rttvar,
805219120Srrs				    vtag,
806219120Srrs				    nbw,
807219397Srrs				    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
808219397Srrs				    net->flight_size,
809219120Srrs				    probepoint);
810219120Srrs				net->cc_mod.rtcc.lbw = nbw;
811219120Srrs				net->cc_mod.rtcc.lbw_rtt = net->rtt;
812219397Srrs				if (net->cc_mod.rtcc.rtt_set_this_sack) {
813219397Srrs					net->cc_mod.rtcc.rtt_set_this_sack = 0;
814219397Srrs					net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes;
815219397Srrs				}
816219120Srrs			}
817219120Srrs		}
818219120Srrs		/*
819171440Srrs		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
820171440Srrs		 * moved.
821171440Srrs		 */
822211944Stuexen		if (accum_moved ||
823216669Stuexen		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
824171440Srrs			/* If the cumulative ack moved we can proceed */
825171440Srrs			if (net->cwnd <= net->ssthresh) {
826171440Srrs				/* We are in slow start */
827179157Srrs				if (net->flight_size + net->net_ack >= net->cwnd) {
828221460Stuexen					uint32_t limit;
829221460Stuexen
830217469Stuexen					old_cwnd = net->cwnd;
831221460Stuexen					switch (asoc->sctp_cmt_on_off) {
832221460Stuexen					case SCTP_CMT_RPV1:
833217469Stuexen						limit = (uint32_t) (((uint64_t) net->mtu *
834217469Stuexen						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
835217469Stuexen						    (uint64_t) net->ssthresh) /
836217469Stuexen						    (uint64_t) t_ssthresh);
837217469Stuexen						incr = (uint32_t) (((uint64_t) net->net_ack *
838217469Stuexen						    (uint64_t) net->ssthresh) /
839217469Stuexen						    (uint64_t) t_ssthresh);
840217469Stuexen						if (incr > limit) {
841217469Stuexen							incr = limit;
842171440Srrs						}
843217469Stuexen						if (incr == 0) {
844217469Stuexen							incr = 1;
845217469Stuexen						}
846221460Stuexen						break;
847221460Stuexen					case SCTP_CMT_RPV2:
848310218Stuexen						/* lastsa>>3;  we don't need
849310218Stuexen						 * to divide ... */
850221460Stuexen						srtt = net->lastsa;
851221460Stuexen						if (srtt == 0) {
852221460Stuexen							srtt = 1;
853221460Stuexen						}
854221460Stuexen						limit = (uint32_t) (((uint64_t) net->mtu *
855221460Stuexen						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
856221460Stuexen						    (uint64_t) net->cwnd) /
857221460Stuexen						    ((uint64_t) srtt * t_ucwnd_sbw));
858221460Stuexen						/* INCREASE FACTOR */
859221460Stuexen						incr = (uint32_t) (((uint64_t) net->net_ack *
860221460Stuexen						    (uint64_t) net->cwnd) /
861221460Stuexen						    ((uint64_t) srtt * t_ucwnd_sbw));
862221460Stuexen						/* INCREASE FACTOR */
863221460Stuexen						if (incr > limit) {
864221460Stuexen							incr = limit;
865221460Stuexen						}
866221460Stuexen						if (incr == 0) {
867221460Stuexen							incr = 1;
868221460Stuexen						}
869221460Stuexen						break;
870221460Stuexen					case SCTP_CMT_MPTCP:
871221460Stuexen						limit = (uint32_t) (((uint64_t) net->mtu *
872221460Stuexen						    mptcp_like_alpha *
873221460Stuexen						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >>
874221460Stuexen						    SHIFT_MPTCP_MULTI);
875221460Stuexen						incr = (uint32_t) (((uint64_t) net->net_ack *
876221460Stuexen						    mptcp_like_alpha) >>
877221460Stuexen						    SHIFT_MPTCP_MULTI);
878221460Stuexen						if (incr > limit) {
879221460Stuexen							incr = limit;
880221460Stuexen						}
881221460Stuexen						if (incr > net->net_ack) {
882221460Stuexen							incr = net->net_ack;
883221460Stuexen						}
884221460Stuexen						if (incr > net->mtu) {
885221460Stuexen							incr = net->mtu;
886221460Stuexen						}
887221460Stuexen						break;
888221460Stuexen					default:
889217469Stuexen						incr = net->net_ack;
890217469Stuexen						if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) {
891217469Stuexen							incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable);
892171440Srrs						}
893221460Stuexen						break;
894171440Srrs					}
895217469Stuexen					net->cwnd += incr;
896279859Stuexen					sctp_enforce_cwnd_limit(asoc, net);
897217469Stuexen					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
898217469Stuexen						sctp_log_cwnd(stcb, net, incr,
899217469Stuexen						    SCTP_CWND_LOG_FROM_SS);
900217469Stuexen					}
901292384Smarkj					SDT_PROBE5(sctp, cwnd, net, ack,
902217469Stuexen					    stcb->asoc.my_vtag,
903217469Stuexen					    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
904217469Stuexen					    net,
905217469Stuexen					    old_cwnd, net->cwnd);
906171440Srrs				} else {
907179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
908171440Srrs						sctp_log_cwnd(stcb, net, net->net_ack,
909171440Srrs						    SCTP_CWND_LOG_NOADV_SS);
910171440Srrs					}
911171440Srrs				}
912171440Srrs			} else {
913171440Srrs				/* We are in congestion avoidance */
914179141Srrs				/*
915179141Srrs				 * Add to pba
916179141Srrs				 */
917179157Srrs				net->partial_bytes_acked += net->net_ack;
918171440Srrs
919179141Srrs				if ((net->flight_size + net->net_ack >= net->cwnd) &&
920179141Srrs				    (net->partial_bytes_acked >= net->cwnd)) {
921179141Srrs					net->partial_bytes_acked -= net->cwnd;
922215817Srrs					old_cwnd = net->cwnd;
923221460Stuexen					switch (asoc->sctp_cmt_on_off) {
924221460Stuexen					case SCTP_CMT_RPV1:
925217469Stuexen						incr = (uint32_t) (((uint64_t) net->mtu *
926217469Stuexen						    (uint64_t) net->ssthresh) /
927217469Stuexen						    (uint64_t) t_ssthresh);
928217469Stuexen						if (incr == 0) {
929217469Stuexen							incr = 1;
930217469Stuexen						}
931221460Stuexen						break;
932221460Stuexen					case SCTP_CMT_RPV2:
933310218Stuexen						/* lastsa>>3;  we don't need
934310218Stuexen						 * to divide ... */
935221460Stuexen						srtt = net->lastsa;
936221460Stuexen						if (srtt == 0) {
937221460Stuexen							srtt = 1;
938221460Stuexen						}
939221460Stuexen						incr = (uint32_t) ((uint64_t) net->mtu *
940221460Stuexen						    (uint64_t) net->cwnd /
941221460Stuexen						    ((uint64_t) srtt *
942221460Stuexen						    t_ucwnd_sbw));
943221460Stuexen						/* INCREASE FACTOR */
944221460Stuexen						if (incr == 0) {
945221460Stuexen							incr = 1;
946221460Stuexen						}
947221460Stuexen						break;
948221460Stuexen					case SCTP_CMT_MPTCP:
949221460Stuexen						incr = (uint32_t) ((mptcp_like_alpha *
950221460Stuexen						    (uint64_t) net->cwnd) >>
951221460Stuexen						    SHIFT_MPTCP_MULTI);
952221460Stuexen						if (incr > net->mtu) {
953221460Stuexen							incr = net->mtu;
954221460Stuexen						}
955221460Stuexen						break;
956221460Stuexen					default:
957217469Stuexen						incr = net->mtu;
958221460Stuexen						break;
959217469Stuexen					}
960217469Stuexen					net->cwnd += incr;
961279859Stuexen					sctp_enforce_cwnd_limit(asoc, net);
962292384Smarkj					SDT_PROBE5(sctp, cwnd, net, ack,
963215817Srrs					    stcb->asoc.my_vtag,
964215817Srrs					    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
965215817Srrs					    net,
966215817Srrs					    old_cwnd, net->cwnd);
967179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
968179141Srrs						sctp_log_cwnd(stcb, net, net->mtu,
969179141Srrs						    SCTP_CWND_LOG_FROM_CA);
970171440Srrs					}
971171440Srrs				} else {
972179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
973171440Srrs						sctp_log_cwnd(stcb, net, net->net_ack,
974171440Srrs						    SCTP_CWND_LOG_NOADV_CA);
975171440Srrs					}
976171440Srrs				}
977171440Srrs			}
978171440Srrs		} else {
979179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
980171440Srrs				sctp_log_cwnd(stcb, net, net->mtu,
981171440Srrs				    SCTP_CWND_LOG_NO_CUMACK);
982171440Srrs			}
983171440Srrs		}
984171440Srrs	}
985171440Srrs}
986171440Srrs
987217611Stuexenstatic void
988224641Stuexensctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
989224641Stuexen{
990224641Stuexen	int old_cwnd;
991224641Stuexen
992224641Stuexen	old_cwnd = net->cwnd;
993224641Stuexen	net->cwnd = net->mtu;
994292384Smarkj	SDT_PROBE5(sctp, cwnd, net, ack,
995224641Stuexen	    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
996224641Stuexen	    old_cwnd, net->cwnd);
997224641Stuexen	SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
998240148Stuexen	    (void *)net, net->cwnd);
999224641Stuexen}
1000224641Stuexen
1001224641Stuexen
1002224641Stuexenstatic void
1003179157Srrssctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
1004171440Srrs{
1005171440Srrs	int old_cwnd = net->cwnd;
1006217469Stuexen	uint32_t t_ssthresh, t_cwnd;
1007221460Stuexen	uint64_t t_ucwnd_sbw;
1008171440Srrs
1009217469Stuexen	/* MT FIXME: Don't compute this over and over again */
1010217469Stuexen	t_ssthresh = 0;
1011217469Stuexen	t_cwnd = 0;
1012221460Stuexen	if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
1013221460Stuexen	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) {
1014217469Stuexen		struct sctp_nets *lnet;
1015221460Stuexen		uint32_t srtt;
1016217469Stuexen
1017221460Stuexen		t_ucwnd_sbw = 0;
1018217469Stuexen		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
1019217469Stuexen			t_ssthresh += lnet->ssthresh;
1020217469Stuexen			t_cwnd += lnet->cwnd;
1021221460Stuexen			srtt = lnet->lastsa;
1022221460Stuexen			/* lastsa>>3;  we don't need to divide ... */
1023221460Stuexen			if (srtt > 0) {
1024221460Stuexen				t_ucwnd_sbw += (uint64_t) lnet->cwnd / (uint64_t) srtt;
1025221460Stuexen			}
1026217469Stuexen		}
1027228907Stuexen		if (t_ssthresh < 1) {
1028228907Stuexen			t_ssthresh = 1;
1029228907Stuexen		}
1030221460Stuexen		if (t_ucwnd_sbw < 1) {
1031221460Stuexen			t_ucwnd_sbw = 1;
1032221460Stuexen		}
1033221460Stuexen		if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) {
1034221460Stuexen			net->ssthresh = (uint32_t) (((uint64_t) 4 *
1035221460Stuexen			    (uint64_t) net->mtu *
1036221460Stuexen			    (uint64_t) net->ssthresh) /
1037221460Stuexen			    (uint64_t) t_ssthresh);
1038221460Stuexen		} else {
1039221460Stuexen			uint64_t cc_delta;
1040221460Stuexen
1041221460Stuexen			srtt = net->lastsa;
1042221460Stuexen			/* lastsa>>3;  we don't need to divide ... */
1043221460Stuexen			if (srtt == 0) {
1044221460Stuexen				srtt = 1;
1045221460Stuexen			}
1046221460Stuexen			cc_delta = t_ucwnd_sbw * (uint64_t) srtt / 2;
1047221460Stuexen			if (cc_delta < t_cwnd) {
1048221460Stuexen				net->ssthresh = (uint32_t) ((uint64_t) t_cwnd - cc_delta);
1049221460Stuexen			} else {
1050221460Stuexen				net->ssthresh = net->mtu;
1051221460Stuexen			}
1052221460Stuexen		}
1053217469Stuexen		if ((net->cwnd > t_cwnd / 2) &&
1054217469Stuexen		    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
1055217469Stuexen			net->ssthresh = net->cwnd - t_cwnd / 2;
1056217469Stuexen		}
1057217469Stuexen		if (net->ssthresh < net->mtu) {
1058217469Stuexen			net->ssthresh = net->mtu;
1059217469Stuexen		}
1060217469Stuexen	} else {
1061217469Stuexen		net->ssthresh = max(net->cwnd / 2, 4 * net->mtu);
1062217469Stuexen	}
1063171440Srrs	net->cwnd = net->mtu;
1064179157Srrs	net->partial_bytes_acked = 0;
1065292384Smarkj	SDT_PROBE5(sctp, cwnd, net, to,
1066215817Srrs	    stcb->asoc.my_vtag,
1067215817Srrs	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1068215817Srrs	    net,
1069215817Srrs	    old_cwnd, net->cwnd);
1070179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1071171440Srrs		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
1072171440Srrs	}
1073171440Srrs}
1074171440Srrs
1075217611Stuexenstatic void
1076219120Srrssctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net,
1077219120Srrs    int in_window, int num_pkt_lost, int use_rtcc)
1078179157Srrs{
1079179157Srrs	int old_cwnd = net->cwnd;
1080179157Srrs
1081219120Srrs	if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) {
1082219120Srrs		/* Data center Congestion Control */
1083219120Srrs		if (in_window == 0) {
1084219120Srrs			/*
1085219120Srrs			 * Go to CA with the cwnd at the point we sent the
1086219120Srrs			 * TSN that was marked with a CE.
1087219120Srrs			 */
1088219120Srrs			if (net->ecn_prev_cwnd < net->cwnd) {
1089219120Srrs				/* Restore to prev cwnd */
1090219120Srrs				net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost);
1091219120Srrs			} else {
1092219120Srrs				/* Just cut in 1/2 */
1093219120Srrs				net->cwnd /= 2;
1094219120Srrs			}
1095219120Srrs			/* Drop to CA */
1096219120Srrs			net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu);
1097219120Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1098219120Srrs				sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1099219120Srrs			}
1100219120Srrs		} else {
1101310218Stuexen			/* Further tuning down required over the drastic
1102310218Stuexen			 * original cut */
1103219120Srrs			net->ssthresh -= (net->mtu * num_pkt_lost);
1104219120Srrs			net->cwnd -= (net->mtu * num_pkt_lost);
1105219120Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1106219120Srrs				sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1107219120Srrs			}
1108219120Srrs		}
1109218129Srrs		SCTP_STAT_INCR(sctps_ecnereducedcwnd);
1110219120Srrs	} else {
1111219120Srrs		if (in_window == 0) {
1112219120Srrs			SCTP_STAT_INCR(sctps_ecnereducedcwnd);
1113219120Srrs			net->ssthresh = net->cwnd / 2;
1114219120Srrs			if (net->ssthresh < net->mtu) {
1115219120Srrs				net->ssthresh = net->mtu;
1116310218Stuexen				/* here back off the timer as well, to slow
1117310218Stuexen				 * us down */
1118219120Srrs				net->RTO <<= 1;
1119219120Srrs			}
1120219120Srrs			net->cwnd = net->ssthresh;
1121292384Smarkj			SDT_PROBE5(sctp, cwnd, net, ecn,
1122219120Srrs			    stcb->asoc.my_vtag,
1123219120Srrs			    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1124219120Srrs			    net,
1125219120Srrs			    old_cwnd, net->cwnd);
1126219120Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1127219120Srrs				sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1128219120Srrs			}
1129218129Srrs		}
1130179157Srrs	}
1131219120Srrs
1132179157Srrs}
1133179157Srrs
1134217611Stuexenstatic void
1135179157Srrssctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
1136179157Srrs    struct sctp_nets *net, struct sctp_pktdrop_chunk *cp,
1137179157Srrs    uint32_t * bottle_bw, uint32_t * on_queue)
1138179157Srrs{
1139179157Srrs	uint32_t bw_avail;
1140218232Srrs	unsigned int incr;
1141179157Srrs	int old_cwnd = net->cwnd;
1142179157Srrs
1143179157Srrs	/* get bottle neck bw */
1144179157Srrs	*bottle_bw = ntohl(cp->bottle_bw);
1145179157Srrs	/* and whats on queue */
1146179157Srrs	*on_queue = ntohl(cp->current_onq);
1147179157Srrs	/*
1148179157Srrs	 * adjust the on-queue if our flight is more it could be that the
1149179157Srrs	 * router has not yet gotten data "in-flight" to it
1150179157Srrs	 */
1151271672Stuexen	if (*on_queue < net->flight_size) {
1152179157Srrs		*on_queue = net->flight_size;
1153271672Stuexen	}
1154271672Stuexen	/* rtt is measured in micro seconds, bottle_bw in bytes per second */
1155271672Stuexen	bw_avail = (uint32_t) (((uint64_t) (*bottle_bw) * net->rtt) / (uint64_t) 1000000);
1156179157Srrs	if (bw_avail > *bottle_bw) {
1157179157Srrs		/*
1158179157Srrs		 * Cap the growth to no more than the bottle neck. This can
1159179157Srrs		 * happen as RTT slides up due to queues. It also means if
1160179157Srrs		 * you have more than a 1 second RTT with a empty queue you
1161179157Srrs		 * will be limited to the bottle_bw per second no matter if
1162179157Srrs		 * other points have 1/2 the RTT and you could get more
1163179157Srrs		 * out...
1164179157Srrs		 */
1165179157Srrs		bw_avail = *bottle_bw;
1166179157Srrs	}
1167179157Srrs	if (*on_queue > bw_avail) {
1168179157Srrs		/*
1169179157Srrs		 * No room for anything else don't allow anything else to be
1170179157Srrs		 * "added to the fire".
1171179157Srrs		 */
1172179157Srrs		int seg_inflight, seg_onqueue, my_portion;
1173179157Srrs
1174179157Srrs		net->partial_bytes_acked = 0;
1175179157Srrs		/* how much are we over queue size? */
1176179157Srrs		incr = *on_queue - bw_avail;
1177179157Srrs		if (stcb->asoc.seen_a_sack_this_pkt) {
1178179157Srrs			/*
1179179157Srrs			 * undo any cwnd adjustment that the sack might have
1180179157Srrs			 * made
1181179157Srrs			 */
1182179157Srrs			net->cwnd = net->prev_cwnd;
1183179157Srrs		}
1184179157Srrs		/* Now how much of that is mine? */
1185179157Srrs		seg_inflight = net->flight_size / net->mtu;
1186179157Srrs		seg_onqueue = *on_queue / net->mtu;
1187179157Srrs		my_portion = (incr * seg_inflight) / seg_onqueue;
1188179157Srrs
1189179157Srrs		/* Have I made an adjustment already */
1190179157Srrs		if (net->cwnd > net->flight_size) {
1191179157Srrs			/*
1192179157Srrs			 * for this flight I made an adjustment we need to
1193179157Srrs			 * decrease the portion by a share our previous
1194179157Srrs			 * adjustment.
1195179157Srrs			 */
1196179157Srrs			int diff_adj;
1197179157Srrs
1198179157Srrs			diff_adj = net->cwnd - net->flight_size;
1199179157Srrs			if (diff_adj > my_portion)
1200179157Srrs				my_portion = 0;
1201179157Srrs			else
1202179157Srrs				my_portion -= diff_adj;
1203179157Srrs		}
1204179157Srrs		/*
1205179157Srrs		 * back down to the previous cwnd (assume we have had a sack
1206179157Srrs		 * before this packet). minus what ever portion of the
1207179157Srrs		 * overage is my fault.
1208179157Srrs		 */
1209179157Srrs		net->cwnd -= my_portion;
1210179157Srrs
1211179157Srrs		/* we will NOT back down more than 1 MTU */
1212179157Srrs		if (net->cwnd <= net->mtu) {
1213179157Srrs			net->cwnd = net->mtu;
1214179157Srrs		}
1215179157Srrs		/* force into CA */
1216179157Srrs		net->ssthresh = net->cwnd - 1;
1217179157Srrs	} else {
1218179157Srrs		/*
1219179157Srrs		 * Take 1/4 of the space left or max burst up .. whichever
1220179157Srrs		 * is less.
1221179157Srrs		 */
1222217894Stuexen		incr = (bw_avail - *on_queue) >> 2;
1223217894Stuexen		if ((stcb->asoc.max_burst > 0) &&
1224217894Stuexen		    (stcb->asoc.max_burst * net->mtu < incr)) {
1225217894Stuexen			incr = stcb->asoc.max_burst * net->mtu;
1226217894Stuexen		}
1227179157Srrs		net->cwnd += incr;
1228179157Srrs	}
1229179157Srrs	if (net->cwnd > bw_avail) {
1230179157Srrs		/* We can't exceed the pipe size */
1231179157Srrs		net->cwnd = bw_avail;
1232179157Srrs	}
1233179157Srrs	if (net->cwnd < net->mtu) {
1234179157Srrs		/* We always have 1 MTU */
1235179157Srrs		net->cwnd = net->mtu;
1236179157Srrs	}
1237279859Stuexen	sctp_enforce_cwnd_limit(&stcb->asoc, net);
1238179157Srrs	if (net->cwnd - old_cwnd != 0) {
1239179157Srrs		/* log only changes */
1240292384Smarkj		SDT_PROBE5(sctp, cwnd, net, pd,
1241215817Srrs		    stcb->asoc.my_vtag,
1242215817Srrs		    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1243215817Srrs		    net,
1244215817Srrs		    old_cwnd, net->cwnd);
1245179783Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1246179157Srrs			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
1247179157Srrs			    SCTP_CWND_LOG_FROM_SAT);
1248179157Srrs		}
1249179157Srrs	}
1250179157Srrs}
1251179157Srrs
1252217611Stuexenstatic void
1253179157Srrssctp_cwnd_update_after_output(struct sctp_tcb *stcb,
1254179157Srrs    struct sctp_nets *net, int burst_limit)
1255179157Srrs{
1256179157Srrs	int old_cwnd = net->cwnd;
1257179157Srrs
1258179157Srrs	if (net->ssthresh < net->cwnd)
1259179157Srrs		net->ssthresh = net->cwnd;
1260219120Srrs	if (burst_limit) {
1261219120Srrs		net->cwnd = (net->flight_size + (burst_limit * net->mtu));
1262279859Stuexen		sctp_enforce_cwnd_limit(&stcb->asoc, net);
1263292384Smarkj		SDT_PROBE5(sctp, cwnd, net, bl,
1264219120Srrs		    stcb->asoc.my_vtag,
1265219120Srrs		    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1266219120Srrs		    net,
1267219120Srrs		    old_cwnd, net->cwnd);
1268219120Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1269219120Srrs			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
1270219120Srrs		}
1271179157Srrs	}
1272179157Srrs}
1273179157Srrs
1274217611Stuexenstatic void
1275219120Srrssctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
1276219120Srrs    struct sctp_association *asoc,
1277219120Srrs    int accum_moved, int reneged_all, int will_exit)
1278219120Srrs{
1279298942Spfg	/* Passing a zero argument in last disables the rtcc algorithm */
1280219120Srrs	sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0);
1281219120Srrs}
1282219120Srrs
1283219120Srrsstatic void
1284219120Srrssctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
1285219120Srrs    int in_window, int num_pkt_lost)
1286219120Srrs{
1287298942Spfg	/* Passing a zero argument in last disables the rtcc algorithm */
1288219120Srrs	sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0);
1289219120Srrs}
1290219120Srrs
1291219120Srrs/* Here starts the RTCCVAR type CC invented by RRS which
1292219120Srrs * is a slight mod to RFC2581. We reuse a common routine or
1293298942Spfg * two since these algorithms are so close and need to
1294219120Srrs * remain the same.
1295219120Srrs */
1296219120Srrsstatic void
1297219120Srrssctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
1298219120Srrs    int in_window, int num_pkt_lost)
1299219120Srrs{
1300219120Srrs	sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1);
1301219120Srrs}
1302219120Srrs
1303219120Srrs
1304219120Srrsstatic
1305219120Srrsvoid
1306219120Srrssctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
1307219120Srrs    struct sctp_tmit_chunk *tp1)
1308219120Srrs{
1309219120Srrs	net->cc_mod.rtcc.bw_bytes += tp1->send_size;
1310219120Srrs}
1311219120Srrs
1312219120Srrsstatic void
1313228653Stuexensctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED,
1314219120Srrs    struct sctp_nets *net)
1315219120Srrs{
1316219120Srrs	if (net->cc_mod.rtcc.tls_needs_set > 0) {
1317219120Srrs		/* We had a bw measurment going on */
1318219120Srrs		struct timeval ltls;
1319219120Srrs
1320219120Srrs		SCTP_GETPTIME_TIMEVAL(&ltls);
1321219120Srrs		timevalsub(&ltls, &net->cc_mod.rtcc.tls);
1322219120Srrs		net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec;
1323219120Srrs	}
1324219120Srrs}
1325219120Srrs
1326219120Srrsstatic void
1327219120Srrssctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
1328219120Srrs    struct sctp_nets *net)
1329219120Srrs{
1330219120Srrs	uint64_t vtag, probepoint;
1331219120Srrs
1332219120Srrs	if (net->cc_mod.rtcc.lbw) {
1333219120Srrs		/* Clear the old bw.. we went to 0 in-flight */
1334219120Srrs		vtag = (net->rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
1335219120Srrs		    (stcb->rport);
1336219120Srrs		probepoint = (((uint64_t) net->cwnd) << 32);
1337219120Srrs		/* Probe point 8 */
1338219120Srrs		probepoint |= ((8 << 16) | 0);
1339292384Smarkj		SDT_PROBE5(sctp, cwnd, net, rttvar,
1340219120Srrs		    vtag,
1341219120Srrs		    ((net->cc_mod.rtcc.lbw << 32) | 0),
1342219397Srrs		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
1343219397Srrs		    net->flight_size,
1344219120Srrs		    probepoint);
1345219120Srrs		net->cc_mod.rtcc.lbw_rtt = 0;
1346219120Srrs		net->cc_mod.rtcc.cwnd_at_bw_set = 0;
1347219120Srrs		net->cc_mod.rtcc.lbw = 0;
1348219397Srrs		net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0;
1349219397Srrs		net->cc_mod.rtcc.vol_reduce = 0;
1350219120Srrs		net->cc_mod.rtcc.bw_tot_time = 0;
1351219120Srrs		net->cc_mod.rtcc.bw_bytes = 0;
1352219120Srrs		net->cc_mod.rtcc.tls_needs_set = 0;
1353219397Srrs		if (net->cc_mod.rtcc.steady_step) {
1354219397Srrs			net->cc_mod.rtcc.vol_reduce = 0;
1355219397Srrs			net->cc_mod.rtcc.step_cnt = 0;
1356219397Srrs			net->cc_mod.rtcc.last_step_state = 0;
1357219397Srrs		}
1358219120Srrs		if (net->cc_mod.rtcc.ret_from_eq) {
1359219120Srrs			/* less aggressive one - reset cwnd too */
1360219120Srrs			uint32_t cwnd_in_mtu, cwnd;
1361219120Srrs
1362219120Srrs			cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
1363219120Srrs			if (cwnd_in_mtu == 0) {
1364310218Stuexen				/* Using 0 means that the value of RFC 4960
1365310218Stuexen				 * is used. */
1366219120Srrs				cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
1367219120Srrs			} else {
1368219120Srrs				/*
1369219120Srrs				 * We take the minimum of the burst limit
1370219120Srrs				 * and the initial congestion window.
1371219120Srrs				 */
1372219120Srrs				if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst))
1373219120Srrs					cwnd_in_mtu = stcb->asoc.max_burst;
1374219120Srrs				cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
1375219120Srrs			}
1376219120Srrs			if (net->cwnd > cwnd) {
1377310218Stuexen				/* Only set if we are not a timeout (i.e.
1378310218Stuexen				 * down to 1 mtu) */
1379219120Srrs				net->cwnd = cwnd;
1380219120Srrs			}
1381219120Srrs		}
1382219120Srrs	}
1383219120Srrs}
1384219120Srrs
1385219120Srrsstatic void
1386219120Srrssctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
1387219120Srrs    struct sctp_nets *net)
1388219120Srrs{
1389219120Srrs	uint64_t vtag, probepoint;
1390219120Srrs
1391219120Srrs	sctp_set_initial_cc_param(stcb, net);
1392219120Srrs	stcb->asoc.use_precise_time = 1;
1393219120Srrs	probepoint = (((uint64_t) net->cwnd) << 32);
1394219120Srrs	probepoint |= ((9 << 16) | 0);
1395219120Srrs	vtag = (net->rtt << 32) |
1396219120Srrs	    (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
1397219120Srrs	    (stcb->rport);
1398292384Smarkj	SDT_PROBE5(sctp, cwnd, net, rttvar,
1399219120Srrs	    vtag,
1400219120Srrs	    0,
1401219120Srrs	    0,
1402219120Srrs	    0,
1403219120Srrs	    probepoint);
1404219120Srrs	net->cc_mod.rtcc.lbw_rtt = 0;
1405219120Srrs	net->cc_mod.rtcc.cwnd_at_bw_set = 0;
1406219397Srrs	net->cc_mod.rtcc.vol_reduce = 0;
1407219120Srrs	net->cc_mod.rtcc.lbw = 0;
1408219397Srrs	net->cc_mod.rtcc.vol_reduce = 0;
1409219397Srrs	net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0;
1410219120Srrs	net->cc_mod.rtcc.bw_tot_time = 0;
1411219120Srrs	net->cc_mod.rtcc.bw_bytes = 0;
1412219120Srrs	net->cc_mod.rtcc.tls_needs_set = 0;
1413219120Srrs	net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret);
1414219397Srrs	net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step);
1415219397Srrs	net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn);
1416219397Srrs	net->cc_mod.rtcc.step_cnt = 0;
1417219397Srrs	net->cc_mod.rtcc.last_step_state = 0;
1418219397Srrs
1419219397Srrs
1420219120Srrs}
1421219120Srrs
1422219120Srrsstatic int
1423219120Srrssctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget,
1424219120Srrs    struct sctp_cc_option *cc_opt)
1425219120Srrs{
1426219120Srrs	struct sctp_nets *net;
1427219120Srrs
1428219120Srrs	if (setorget == 1) {
1429219120Srrs		/* a set */
1430219120Srrs		if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
1431219120Srrs			if ((cc_opt->aid_value.assoc_value != 0) &&
1432219120Srrs			    (cc_opt->aid_value.assoc_value != 1)) {
1433219120Srrs				return (EINVAL);
1434219120Srrs			}
1435219120Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1436219120Srrs				net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value;
1437219120Srrs			}
1438219120Srrs		} else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
1439219120Srrs			if ((cc_opt->aid_value.assoc_value != 0) &&
1440219120Srrs			    (cc_opt->aid_value.assoc_value != 1)) {
1441219120Srrs				return (EINVAL);
1442219120Srrs			}
1443219120Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1444219120Srrs				net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value;
1445219120Srrs			}
1446219397Srrs		} else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) {
1447219397Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1448219397Srrs				net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value;
1449219397Srrs			}
1450219120Srrs		} else {
1451219120Srrs			return (EINVAL);
1452219120Srrs		}
1453219120Srrs	} else {
1454219120Srrs		/* a get */
1455219120Srrs		if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
1456219120Srrs			net = TAILQ_FIRST(&stcb->asoc.nets);
1457219120Srrs			if (net == NULL) {
1458219120Srrs				return (EFAULT);
1459219120Srrs			}
1460219120Srrs			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq;
1461219120Srrs		} else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
1462219120Srrs			net = TAILQ_FIRST(&stcb->asoc.nets);
1463219120Srrs			if (net == NULL) {
1464219120Srrs				return (EFAULT);
1465219120Srrs			}
1466219120Srrs			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn;
1467219397Srrs		} else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) {
1468219397Srrs			net = TAILQ_FIRST(&stcb->asoc.nets);
1469219397Srrs			if (net == NULL) {
1470219397Srrs				return (EFAULT);
1471219397Srrs			}
1472219397Srrs			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step;
1473219120Srrs		} else {
1474219120Srrs			return (EINVAL);
1475219120Srrs		}
1476219120Srrs	}
1477219120Srrs	return (0);
1478219120Srrs}
1479219120Srrs
1480219120Srrsstatic void
1481228653Stuexensctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED,
1482219120Srrs    struct sctp_nets *net)
1483219120Srrs{
1484219120Srrs	if (net->cc_mod.rtcc.tls_needs_set == 0) {
1485219120Srrs		SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls);
1486219120Srrs		net->cc_mod.rtcc.tls_needs_set = 2;
1487219120Srrs	}
1488219120Srrs}
1489219120Srrs
1490219120Srrsstatic void
1491219120Srrssctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb,
1492219120Srrs    struct sctp_association *asoc,
1493219120Srrs    int accum_moved, int reneged_all, int will_exit)
1494219120Srrs{
1495298942Spfg	/* Passing a one argument at the last enables the rtcc algorithm */
1496219120Srrs	sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1);
1497219120Srrs}
1498219120Srrs
1499219397Srrsstatic void
1500228653Stuexensctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED,
1501228653Stuexen    struct sctp_nets *net,
1502228653Stuexen    struct timeval *now SCTP_UNUSED)
1503219397Srrs{
1504219397Srrs	net->cc_mod.rtcc.rtt_set_this_sack = 1;
1505219397Srrs}
1506219120Srrs
1507219120Srrs/* Here starts Sally Floyds HS-TCP */
1508219120Srrs
1509171440Srrsstruct sctp_hs_raise_drop {
1510171440Srrs	int32_t cwnd;
1511297208Stuexen	int8_t increase;
1512297208Stuexen	int8_t drop_percent;
1513171440Srrs};
1514171440Srrs
1515171440Srrs#define SCTP_HS_TABLE_SIZE 73
1516171440Srrs
1517297208Stuexenstatic const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
1518171440Srrs	{38, 1, 50},		/* 0   */
1519171440Srrs	{118, 2, 44},		/* 1   */
1520171440Srrs	{221, 3, 41},		/* 2   */
1521171440Srrs	{347, 4, 38},		/* 3   */
1522171440Srrs	{495, 5, 37},		/* 4   */
1523171440Srrs	{663, 6, 35},		/* 5   */
1524171440Srrs	{851, 7, 34},		/* 6   */
1525171440Srrs	{1058, 8, 33},		/* 7   */
1526171440Srrs	{1284, 9, 32},		/* 8   */
1527171440Srrs	{1529, 10, 31},		/* 9   */
1528171440Srrs	{1793, 11, 30},		/* 10  */
1529171440Srrs	{2076, 12, 29},		/* 11  */
1530171440Srrs	{2378, 13, 28},		/* 12  */
1531171440Srrs	{2699, 14, 28},		/* 13  */
1532171440Srrs	{3039, 15, 27},		/* 14  */
1533171440Srrs	{3399, 16, 27},		/* 15  */
1534171440Srrs	{3778, 17, 26},		/* 16  */
1535171440Srrs	{4177, 18, 26},		/* 17  */
1536171440Srrs	{4596, 19, 25},		/* 18  */
1537171440Srrs	{5036, 20, 25},		/* 19  */
1538171440Srrs	{5497, 21, 24},		/* 20  */
1539171440Srrs	{5979, 22, 24},		/* 21  */
1540171440Srrs	{6483, 23, 23},		/* 22  */
1541171440Srrs	{7009, 24, 23},		/* 23  */
1542171440Srrs	{7558, 25, 22},		/* 24  */
1543171440Srrs	{8130, 26, 22},		/* 25  */
1544171440Srrs	{8726, 27, 22},		/* 26  */
1545171440Srrs	{9346, 28, 21},		/* 27  */
1546171440Srrs	{9991, 29, 21},		/* 28  */
1547171440Srrs	{10661, 30, 21},	/* 29  */
1548171440Srrs	{11358, 31, 20},	/* 30  */
1549171440Srrs	{12082, 32, 20},	/* 31  */
1550171440Srrs	{12834, 33, 20},	/* 32  */
1551171440Srrs	{13614, 34, 19},	/* 33  */
1552171440Srrs	{14424, 35, 19},	/* 34  */
1553171440Srrs	{15265, 36, 19},	/* 35  */
1554171440Srrs	{16137, 37, 19},	/* 36  */
1555171440Srrs	{17042, 38, 18},	/* 37  */
1556171440Srrs	{17981, 39, 18},	/* 38  */
1557171440Srrs	{18955, 40, 18},	/* 39  */
1558171440Srrs	{19965, 41, 17},	/* 40  */
1559171440Srrs	{21013, 42, 17},	/* 41  */
1560171440Srrs	{22101, 43, 17},	/* 42  */
1561171440Srrs	{23230, 44, 17},	/* 43  */
1562171440Srrs	{24402, 45, 16},	/* 44  */
1563171440Srrs	{25618, 46, 16},	/* 45  */
1564171440Srrs	{26881, 47, 16},	/* 46  */
1565171440Srrs	{28193, 48, 16},	/* 47  */
1566171440Srrs	{29557, 49, 15},	/* 48  */
1567171440Srrs	{30975, 50, 15},	/* 49  */
1568171440Srrs	{32450, 51, 15},	/* 50  */
1569171440Srrs	{33986, 52, 15},	/* 51  */
1570171440Srrs	{35586, 53, 14},	/* 52  */
1571171440Srrs	{37253, 54, 14},	/* 53  */
1572171440Srrs	{38992, 55, 14},	/* 54  */
1573171440Srrs	{40808, 56, 14},	/* 55  */
1574171440Srrs	{42707, 57, 13},	/* 56  */
1575171440Srrs	{44694, 58, 13},	/* 57  */
1576171440Srrs	{46776, 59, 13},	/* 58  */
1577171440Srrs	{48961, 60, 13},	/* 59  */
1578171440Srrs	{51258, 61, 13},	/* 60  */
1579171440Srrs	{53677, 62, 12},	/* 61  */
1580171440Srrs	{56230, 63, 12},	/* 62  */
1581171440Srrs	{58932, 64, 12},	/* 63  */
1582171440Srrs	{61799, 65, 12},	/* 64  */
1583171440Srrs	{64851, 66, 11},	/* 65  */
1584171440Srrs	{68113, 67, 11},	/* 66  */
1585171440Srrs	{71617, 68, 11},	/* 67  */
1586171440Srrs	{75401, 69, 10},	/* 68  */
1587171440Srrs	{79517, 70, 10},	/* 69  */
1588171440Srrs	{84035, 71, 10},	/* 70  */
1589171440Srrs	{89053, 72, 10},	/* 71  */
1590171440Srrs	{94717, 73, 9}		/* 72  */
1591171440Srrs};
1592171440Srrs
1593171440Srrsstatic void
1594171440Srrssctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
1595171440Srrs{
1596171440Srrs	int cur_val, i, indx, incr;
1597279859Stuexen	int old_cwnd = net->cwnd;
1598171440Srrs
1599171440Srrs	cur_val = net->cwnd >> 10;
1600171440Srrs	indx = SCTP_HS_TABLE_SIZE - 1;
1601234995Stuexen
1602171440Srrs	if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1603171440Srrs		/* normal mode */
1604171440Srrs		if (net->net_ack > net->mtu) {
1605171440Srrs			net->cwnd += net->mtu;
1606171440Srrs		} else {
1607171440Srrs			net->cwnd += net->net_ack;
1608171440Srrs		}
1609171440Srrs	} else {
1610171440Srrs		for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) {
1611171440Srrs			if (cur_val < sctp_cwnd_adjust[i].cwnd) {
1612171440Srrs				indx = i;
1613171440Srrs				break;
1614171440Srrs			}
1615171440Srrs		}
1616171440Srrs		net->last_hs_used = indx;
1617297208Stuexen		incr = (((int32_t) sctp_cwnd_adjust[indx].increase) << 10);
1618171440Srrs		net->cwnd += incr;
1619171440Srrs	}
1620279859Stuexen	sctp_enforce_cwnd_limit(&stcb->asoc, net);
1621279859Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1622279859Stuexen		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS);
1623279859Stuexen	}
1624171440Srrs}
1625171440Srrs
1626171440Srrsstatic void
1627171440Srrssctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
1628171440Srrs{
1629171440Srrs	int cur_val, i, indx;
1630171440Srrs	int old_cwnd = net->cwnd;
1631171440Srrs
1632171440Srrs	cur_val = net->cwnd >> 10;
1633171440Srrs	if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1634171440Srrs		/* normal mode */
1635171440Srrs		net->ssthresh = net->cwnd / 2;
1636171440Srrs		if (net->ssthresh < (net->mtu * 2)) {
1637171440Srrs			net->ssthresh = 2 * net->mtu;
1638171440Srrs		}
1639171440Srrs		net->cwnd = net->ssthresh;
1640171440Srrs	} else {
1641171440Srrs		/* drop by the proper amount */
1642171440Srrs		net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
1643297208Stuexen		    (int32_t) sctp_cwnd_adjust[net->last_hs_used].drop_percent);
1644171440Srrs		net->cwnd = net->ssthresh;
1645171440Srrs		/* now where are we */
1646171440Srrs		indx = net->last_hs_used;
1647171440Srrs		cur_val = net->cwnd >> 10;
1648171440Srrs		/* reset where we are in the table */
1649171440Srrs		if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1650171440Srrs			/* feel out of hs */
1651171440Srrs			net->last_hs_used = 0;
1652171440Srrs		} else {
1653171440Srrs			for (i = indx; i >= 1; i--) {
1654171440Srrs				if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) {
1655171440Srrs					break;
1656171440Srrs				}
1657171440Srrs			}
1658171440Srrs			net->last_hs_used = indx;
1659171440Srrs		}
1660171440Srrs	}
1661279859Stuexen	sctp_enforce_cwnd_limit(&stcb->asoc, net);
1662179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1663171440Srrs		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR);
1664171440Srrs	}
1665171440Srrs}
1666171440Srrs
1667217611Stuexenstatic void
1668171440Srrssctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
1669171440Srrs    struct sctp_association *asoc)
1670171440Srrs{
1671171440Srrs	struct sctp_nets *net;
1672171440Srrs
1673171440Srrs	/*
1674216669Stuexen	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
1675171440Srrs	 * (net->fast_retran_loss_recovery == 0)))
1676171440Srrs	 */
1677171440Srrs	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1678211944Stuexen		if ((asoc->fast_retran_loss_recovery == 0) ||
1679216669Stuexen		    (asoc->sctp_cmt_on_off > 0)) {
1680171440Srrs			/* out of a RFC2582 Fast recovery window? */
1681171440Srrs			if (net->net_ack > 0) {
1682171440Srrs				/*
1683171440Srrs				 * per section 7.2.3, are there any
1684171440Srrs				 * destinations that had a fast retransmit
1685171440Srrs				 * to them. If so what we need to do is
1686171440Srrs				 * adjust ssthresh and cwnd.
1687171440Srrs				 */
1688171440Srrs				struct sctp_tmit_chunk *lchk;
1689171440Srrs
1690171440Srrs				sctp_hs_cwnd_decrease(stcb, net);
1691171440Srrs
1692171440Srrs				lchk = TAILQ_FIRST(&asoc->send_queue);
1693171440Srrs
1694171440Srrs				net->partial_bytes_acked = 0;
1695171440Srrs				/* Turn on fast recovery window */
1696171440Srrs				asoc->fast_retran_loss_recovery = 1;
1697171440Srrs				if (lchk == NULL) {
1698171440Srrs					/* Mark end of the window */
1699171440Srrs					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
1700171440Srrs				} else {
1701171440Srrs					asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
1702171440Srrs				}
1703171440Srrs
1704171440Srrs				/*
1705171440Srrs				 * CMT fast recovery -- per destination
1706171440Srrs				 * recovery variable.
1707171440Srrs				 */
1708171440Srrs				net->fast_retran_loss_recovery = 1;
1709171440Srrs
1710171440Srrs				if (lchk == NULL) {
1711171440Srrs					/* Mark end of the window */
1712171440Srrs					net->fast_recovery_tsn = asoc->sending_seq - 1;
1713171440Srrs				} else {
1714171440Srrs					net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
1715171440Srrs				}
1716171440Srrs
1717171440Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
1718283650Stuexen				    stcb->sctp_ep, stcb, net,
1719283650Stuexen				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2);
1720171440Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
1721171440Srrs				    stcb->sctp_ep, stcb, net);
1722171440Srrs			}
1723171440Srrs		} else if (net->net_ack > 0) {
1724171440Srrs			/*
1725171440Srrs			 * Mark a peg that we WOULD have done a cwnd
1726171440Srrs			 * reduction but RFC2582 prevented this action.
1727171440Srrs			 */
1728171440Srrs			SCTP_STAT_INCR(sctps_fastretransinrtt);
1729171440Srrs		}
1730171440Srrs	}
1731171440Srrs}
1732171440Srrs
1733217611Stuexenstatic void
1734171440Srrssctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
1735171440Srrs    struct sctp_association *asoc,
1736228653Stuexen    int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
1737171440Srrs{
1738171440Srrs	struct sctp_nets *net;
1739171440Srrs
1740171440Srrs	/******************************/
1741171440Srrs	/* update cwnd and Early FR   */
1742171440Srrs	/******************************/
1743171440Srrs	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1744171440Srrs
1745171440Srrs#ifdef JANA_CMT_FAST_RECOVERY
1746171440Srrs		/*
1747171440Srrs		 * CMT fast recovery code. Need to debug.
1748171440Srrs		 */
1749171440Srrs		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
1750217469Stuexen			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
1751217469Stuexen			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
1752171440Srrs				net->will_exit_fast_recovery = 1;
1753171440Srrs			}
1754171440Srrs		}
1755171440Srrs#endif
1756171440Srrs		/* if nothing was acked on this destination skip it */
1757171440Srrs		if (net->net_ack == 0) {
1758179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1759171440Srrs				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
1760171440Srrs			}
1761171440Srrs			continue;
1762171440Srrs		}
1763171440Srrs#ifdef JANA_CMT_FAST_RECOVERY
1764171440Srrs		/*
1765171440Srrs		 * CMT fast recovery code
1766171440Srrs		 */
1767171440Srrs		/*
1768216669Stuexen		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
1769216669Stuexen		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
1770216669Stuexen		 * } else if (sctp_cmt_on_off == 0 &&
1771171440Srrs		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
1772171440Srrs		 */
1773171440Srrs#endif
1774171440Srrs
1775211944Stuexen		if (asoc->fast_retran_loss_recovery &&
1776211944Stuexen		    (will_exit == 0) &&
1777211944Stuexen		    (asoc->sctp_cmt_on_off == 0)) {
1778171440Srrs			/*
1779171440Srrs			 * If we are in loss recovery we skip any cwnd
1780171440Srrs			 * update
1781171440Srrs			 */
1782224641Stuexen			return;
1783171440Srrs		}
1784171440Srrs		/*
1785171440Srrs		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
1786171440Srrs		 * moved.
1787171440Srrs		 */
1788211944Stuexen		if (accum_moved ||
1789216669Stuexen		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
1790171440Srrs			/* If the cumulative ack moved we can proceed */
1791171440Srrs			if (net->cwnd <= net->ssthresh) {
1792171440Srrs				/* We are in slow start */
1793179157Srrs				if (net->flight_size + net->net_ack >= net->cwnd) {
1794171440Srrs					sctp_hs_cwnd_increase(stcb, net);
1795171440Srrs				} else {
1796179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1797171440Srrs						sctp_log_cwnd(stcb, net, net->net_ack,
1798171440Srrs						    SCTP_CWND_LOG_NOADV_SS);
1799171440Srrs					}
1800171440Srrs				}
1801171440Srrs			} else {
1802171440Srrs				/* We are in congestion avoidance */
1803179157Srrs				net->partial_bytes_acked += net->net_ack;
1804179157Srrs				if ((net->flight_size + net->net_ack >= net->cwnd) &&
1805179157Srrs				    (net->partial_bytes_acked >= net->cwnd)) {
1806179157Srrs					net->partial_bytes_acked -= net->cwnd;
1807179157Srrs					net->cwnd += net->mtu;
1808279859Stuexen					sctp_enforce_cwnd_limit(asoc, net);
1809179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1810179157Srrs						sctp_log_cwnd(stcb, net, net->mtu,
1811179157Srrs						    SCTP_CWND_LOG_FROM_CA);
1812171440Srrs					}
1813171440Srrs				} else {
1814179783Srrs					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1815171440Srrs						sctp_log_cwnd(stcb, net, net->net_ack,
1816171440Srrs						    SCTP_CWND_LOG_NOADV_CA);
1817171440Srrs					}
1818171440Srrs				}
1819171440Srrs			}
1820171440Srrs		} else {
1821179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1822171440Srrs				sctp_log_cwnd(stcb, net, net->mtu,
1823171440Srrs				    SCTP_CWND_LOG_NO_CUMACK);
1824171440Srrs			}
1825171440Srrs		}
1826171440Srrs	}
1827171440Srrs}
1828171440Srrs
1829171440Srrs
1830171440Srrs/*
1831171440Srrs * H-TCP congestion control. The algorithm is detailed in:
1832171440Srrs * R.N.Shorten, D.J.Leith:
1833171440Srrs *   "H-TCP: TCP for high-speed and long-distance networks"
1834171440Srrs *   Proc. PFLDnet, Argonne, 2004.
1835171440Srrs * http://www.hamilton.ie/net/htcp3.pdf
1836171440Srrs */
1837171440Srrs
1838171440Srrs
1839171440Srrsstatic int use_rtt_scaling = 1;
1840171440Srrsstatic int use_bandwidth_switch = 1;
1841171440Srrs
1842171440Srrsstatic inline int
1843171440Srrsbetween(uint32_t seq1, uint32_t seq2, uint32_t seq3)
1844171440Srrs{
1845228907Stuexen	return (seq3 - seq2 >= seq1 - seq2);
1846171440Srrs}
1847171440Srrs
1848171440Srrsstatic inline uint32_t
1849171440Srrshtcp_cong_time(struct htcp *ca)
1850171440Srrs{
1851228907Stuexen	return (sctp_get_tick_count() - ca->last_cong);
1852171440Srrs}
1853171440Srrs
1854171440Srrsstatic inline uint32_t
1855171440Srrshtcp_ccount(struct htcp *ca)
1856171440Srrs{
1857228907Stuexen	return (htcp_cong_time(ca) / ca->minRTT);
1858171440Srrs}
1859171440Srrs
1860171440Srrsstatic inline void
1861171440Srrshtcp_reset(struct htcp *ca)
1862171440Srrs{
1863171440Srrs	ca->undo_last_cong = ca->last_cong;
1864171440Srrs	ca->undo_maxRTT = ca->maxRTT;
1865171440Srrs	ca->undo_old_maxB = ca->old_maxB;
1866171477Srrs	ca->last_cong = sctp_get_tick_count();
1867171440Srrs}
1868171440Srrs
1869171440Srrs#ifdef SCTP_NOT_USED
1870171440Srrs
1871171440Srrsstatic uint32_t
1872171440Srrshtcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net)
1873171440Srrs{
1874219057Srrs	net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong;
1875219057Srrs	net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT;
1876219057Srrs	net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB;
1877228907Stuexen	return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu));
1878171440Srrs}
1879171440Srrs
1880171440Srrs#endif
1881171440Srrs
1882171440Srrsstatic inline void
1883228653Stuexenmeasure_rtt(struct sctp_nets *net)
1884171440Srrs{
1885219014Stuexen	uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT;
1886171440Srrs
1887171440Srrs	/* keep track of minimum RTT seen so far, minRTT is zero at first */
1888219057Srrs	if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT)
1889219057Srrs		net->cc_mod.htcp_ca.minRTT = srtt;
1890171440Srrs
1891171440Srrs	/* max RTT */
1892219057Srrs	if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) {
1893219057Srrs		if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT)
1894219057Srrs			net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT;
1895219057Srrs		if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + MSEC_TO_TICKS(20))
1896219057Srrs			net->cc_mod.htcp_ca.maxRTT = srtt;
1897171440Srrs	}
1898171440Srrs}
1899171440Srrs
1900171440Srrsstatic void
1901228653Stuexenmeasure_achieved_throughput(struct sctp_nets *net)
1902171440Srrs{
1903171477Srrs	uint32_t now = sctp_get_tick_count();
1904171440Srrs
1905171440Srrs	if (net->fast_retran_ip == 0)
1906219057Srrs		net->cc_mod.htcp_ca.bytes_acked = net->net_ack;
1907171440Srrs
1908171440Srrs	if (!use_bandwidth_switch)
1909171440Srrs		return;
1910171440Srrs
1911171440Srrs	/* achieved throughput calculations */
1912171440Srrs	/* JRS - not 100% sure of this statement */
1913171440Srrs	if (net->fast_retran_ip == 1) {
1914219057Srrs		net->cc_mod.htcp_ca.bytecount = 0;
1915219057Srrs		net->cc_mod.htcp_ca.lasttime = now;
1916171440Srrs		return;
1917171440Srrs	}
1918219057Srrs	net->cc_mod.htcp_ca.bytecount += net->net_ack;
1919240158Stuexen	if ((net->cc_mod.htcp_ca.bytecount >= net->cwnd - (((net->cc_mod.htcp_ca.alpha >> 7) ? (net->cc_mod.htcp_ca.alpha >> 7) : 1) * net->mtu)) &&
1920240158Stuexen	    (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) &&
1921240158Stuexen	    (net->cc_mod.htcp_ca.minRTT > 0)) {
1922219057Srrs		uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime);
1923171440Srrs
1924219057Srrs		if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) {
1925171440Srrs			/* just after backoff */
1926219057Srrs			net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi;
1927171440Srrs		} else {
1928219057Srrs			net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4;
1929219057Srrs			if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB)
1930219057Srrs				net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi;
1931219057Srrs			if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB)
1932219057Srrs				net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB;
1933171440Srrs		}
1934219057Srrs		net->cc_mod.htcp_ca.bytecount = 0;
1935219057Srrs		net->cc_mod.htcp_ca.lasttime = now;
1936171440Srrs	}
1937171440Srrs}
1938171440Srrs
1939171440Srrsstatic inline void
1940171440Srrshtcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT)
1941171440Srrs{
1942171440Srrs	if (use_bandwidth_switch) {
1943171440Srrs		uint32_t maxB = ca->maxB;
1944171440Srrs		uint32_t old_maxB = ca->old_maxB;
1945171440Srrs
1946171440Srrs		ca->old_maxB = ca->maxB;
1947171440Srrs
1948171440Srrs		if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
1949171440Srrs			ca->beta = BETA_MIN;
1950171440Srrs			ca->modeswitch = 0;
1951171440Srrs			return;
1952171440Srrs		}
1953171440Srrs	}
1954171440Srrs	if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) {
1955171440Srrs		ca->beta = (minRTT << 7) / maxRTT;
1956171440Srrs		if (ca->beta < BETA_MIN)
1957171440Srrs			ca->beta = BETA_MIN;
1958171440Srrs		else if (ca->beta > BETA_MAX)
1959171440Srrs			ca->beta = BETA_MAX;
1960171440Srrs	} else {
1961171440Srrs		ca->beta = BETA_MIN;
1962171440Srrs		ca->modeswitch = 1;
1963171440Srrs	}
1964171440Srrs}
1965171440Srrs
1966171440Srrsstatic inline void
1967171440Srrshtcp_alpha_update(struct htcp *ca)
1968171440Srrs{
1969171440Srrs	uint32_t minRTT = ca->minRTT;
1970171440Srrs	uint32_t factor = 1;
1971171440Srrs	uint32_t diff = htcp_cong_time(ca);
1972171440Srrs
1973171440Srrs	if (diff > (uint32_t) hz) {
1974171440Srrs		diff -= hz;
1975171440Srrs		factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz;
1976171440Srrs	}
1977171440Srrs	if (use_rtt_scaling && minRTT) {
1978171440Srrs		uint32_t scale = (hz << 3) / (10 * minRTT);
1979171440Srrs
1980171440Srrs		scale = min(max(scale, 1U << 2), 10U << 3);	/* clamping ratio to
1981171440Srrs								 * interval [0.5,10]<<3 */
1982171440Srrs		factor = (factor << 3) / scale;
1983171440Srrs		if (!factor)
1984171440Srrs			factor = 1;
1985171440Srrs	}
1986171440Srrs	ca->alpha = 2 * factor * ((1 << 7) - ca->beta);
1987171440Srrs	if (!ca->alpha)
1988171440Srrs		ca->alpha = ALPHA_BASE;
1989171440Srrs}
1990171440Srrs
1991171440Srrs/* After we have the rtt data to calculate beta, we'd still prefer to wait one
1992171440Srrs * rtt before we adjust our beta to ensure we are working from a consistent
1993171440Srrs * data.
1994171440Srrs *
1995171440Srrs * This function should be called when we hit a congestion event since only at
1996171440Srrs * that point do we really have a real sense of maxRTT (the queues en route
1997171440Srrs * were getting just too full now).
1998171440Srrs */
1999171440Srrsstatic void
2000228653Stuexenhtcp_param_update(struct sctp_nets *net)
2001171440Srrs{
2002219057Srrs	uint32_t minRTT = net->cc_mod.htcp_ca.minRTT;
2003219057Srrs	uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT;
2004171440Srrs
2005219057Srrs	htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT);
2006219057Srrs	htcp_alpha_update(&net->cc_mod.htcp_ca);
2007171440Srrs
2008310218Stuexen	/* add slowly fading memory for maxRTT to accommodate routing
2009310218Stuexen	 * changes etc */
2010171440Srrs	if (minRTT > 0 && maxRTT > minRTT)
2011219057Srrs		net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100;
2012171440Srrs}
2013171440Srrs
2014171440Srrsstatic uint32_t
2015228653Stuexenhtcp_recalc_ssthresh(struct sctp_nets *net)
2016171440Srrs{
2017228653Stuexen	htcp_param_update(net);
2018228907Stuexen	return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu));
2019171440Srrs}
2020171440Srrs
2021171440Srrsstatic void
2022171440Srrshtcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
2023171440Srrs{
2024171440Srrs	/*-
2025171440Srrs	 * How to handle these functions?
2026171440Srrs         *	if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question.
2027171440Srrs	 *		return;
2028171440Srrs	 */
2029171440Srrs	if (net->cwnd <= net->ssthresh) {
2030171440Srrs		/* We are in slow start */
2031171440Srrs		if (net->flight_size + net->net_ack >= net->cwnd) {
2032179783Srrs			if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) {
2033179783Srrs				net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable));
2034179783Srrs				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2035171440Srrs					sctp_log_cwnd(stcb, net, net->mtu,
2036171440Srrs					    SCTP_CWND_LOG_FROM_SS);
2037171440Srrs				}
2038171440Srrs			} else {
2039171440Srrs				net->cwnd += net->net_ack;
2040179783Srrs				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2041171440Srrs					sctp_log_cwnd(stcb, net, net->net_ack,
2042171440Srrs					    SCTP_CWND_LOG_FROM_SS);
2043171440Srrs				}
2044171440Srrs			}
2045279859Stuexen			sctp_enforce_cwnd_limit(&stcb->asoc, net);
2046171440Srrs		} else {
2047179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2048171440Srrs				sctp_log_cwnd(stcb, net, net->net_ack,
2049171440Srrs				    SCTP_CWND_LOG_NOADV_SS);
2050171440Srrs			}
2051171440Srrs		}
2052171440Srrs	} else {
2053228653Stuexen		measure_rtt(net);
2054171440Srrs
2055171440Srrs		/*
2056171440Srrs		 * In dangerous area, increase slowly. In theory this is
2057171440Srrs		 * net->cwnd += alpha / net->cwnd
2058171440Srrs		 */
2059171440Srrs		/* What is snd_cwnd_cnt?? */
2060219057Srrs		if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) {
2061171440Srrs			/*-
2062171440Srrs			 * Does SCTP have a cwnd clamp?
2063171440Srrs			 * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS).
2064171440Srrs			 */
2065171440Srrs			net->cwnd += net->mtu;
2066171440Srrs			net->partial_bytes_acked = 0;
2067279859Stuexen			sctp_enforce_cwnd_limit(&stcb->asoc, net);
2068219057Srrs			htcp_alpha_update(&net->cc_mod.htcp_ca);
2069179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2070171440Srrs				sctp_log_cwnd(stcb, net, net->mtu,
2071171440Srrs				    SCTP_CWND_LOG_FROM_CA);
2072171440Srrs			}
2073171440Srrs		} else {
2074171440Srrs			net->partial_bytes_acked += net->net_ack;
2075179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2076171440Srrs				sctp_log_cwnd(stcb, net, net->net_ack,
2077171440Srrs				    SCTP_CWND_LOG_NOADV_CA);
2078171440Srrs			}
2079171440Srrs		}
2080171440Srrs
2081219057Srrs		net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2082171440Srrs	}
2083171440Srrs}
2084171440Srrs
2085171440Srrs#ifdef SCTP_NOT_USED
2086171440Srrs/* Lower bound on congestion window. */
2087171440Srrsstatic uint32_t
2088171440Srrshtcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net)
2089171440Srrs{
2090228907Stuexen	return (net->ssthresh);
2091171440Srrs}
2092171440Srrs#endif
2093171440Srrs
2094171440Srrsstatic void
2095228653Stuexenhtcp_init(struct sctp_nets *net)
2096171440Srrs{
2097219057Srrs	memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp));
2098219057Srrs	net->cc_mod.htcp_ca.alpha = ALPHA_BASE;
2099219057Srrs	net->cc_mod.htcp_ca.beta = BETA_MIN;
2100219057Srrs	net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2101219057Srrs	net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
2102171440Srrs}
2103171440Srrs
2104217611Stuexenstatic void
2105171440Srrssctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
2106171440Srrs{
2107171440Srrs	/*
2108171440Srrs	 * We take the max of the burst limit times a MTU or the
2109171440Srrs	 * INITIAL_CWND. We then limit this to 4 MTU's of sending.
2110171440Srrs	 */
2111171440Srrs	net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
2112171440Srrs	net->ssthresh = stcb->asoc.peers_rwnd;
2113279859Stuexen	sctp_enforce_cwnd_limit(&stcb->asoc, net);
2114228653Stuexen	htcp_init(net);
2115171440Srrs
2116179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
2117171440Srrs		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
2118171440Srrs	}
2119171440Srrs}
2120171440Srrs
2121217611Stuexenstatic void
2122171440Srrssctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
2123171440Srrs    struct sctp_association *asoc,
2124228653Stuexen    int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
2125171440Srrs{
2126171440Srrs	struct sctp_nets *net;
2127171440Srrs
2128171440Srrs	/******************************/
2129171440Srrs	/* update cwnd and Early FR   */
2130171440Srrs	/******************************/
2131171440Srrs	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2132171440Srrs
2133171440Srrs#ifdef JANA_CMT_FAST_RECOVERY
2134171440Srrs		/*
2135171440Srrs		 * CMT fast recovery code. Need to debug.
2136171440Srrs		 */
2137171440Srrs		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
2138217469Stuexen			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
2139217469Stuexen			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
2140171440Srrs				net->will_exit_fast_recovery = 1;
2141171440Srrs			}
2142171440Srrs		}
2143171440Srrs#endif
2144171440Srrs		/* if nothing was acked on this destination skip it */
2145171440Srrs		if (net->net_ack == 0) {
2146179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2147171440Srrs				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
2148171440Srrs			}
2149171440Srrs			continue;
2150171440Srrs		}
2151171440Srrs#ifdef JANA_CMT_FAST_RECOVERY
2152171440Srrs		/*
2153171440Srrs		 * CMT fast recovery code
2154171440Srrs		 */
2155171440Srrs		/*
2156216669Stuexen		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
2157216669Stuexen		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
2158216669Stuexen		 * } else if (sctp_cmt_on_off == 0 &&
2159171440Srrs		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
2160171440Srrs		 */
2161171440Srrs#endif
2162171440Srrs
2163211944Stuexen		if (asoc->fast_retran_loss_recovery &&
2164211944Stuexen		    will_exit == 0 &&
2165211944Stuexen		    (asoc->sctp_cmt_on_off == 0)) {
2166171440Srrs			/*
2167171440Srrs			 * If we are in loss recovery we skip any cwnd
2168171440Srrs			 * update
2169171440Srrs			 */
2170224641Stuexen			return;
2171171440Srrs		}
2172171440Srrs		/*
2173171440Srrs		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
2174171440Srrs		 * moved.
2175171440Srrs		 */
2176211944Stuexen		if (accum_moved ||
2177216669Stuexen		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
2178171440Srrs			htcp_cong_avoid(stcb, net);
2179228653Stuexen			measure_achieved_throughput(net);
2180171440Srrs		} else {
2181179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2182171440Srrs				sctp_log_cwnd(stcb, net, net->mtu,
2183171440Srrs				    SCTP_CWND_LOG_NO_CUMACK);
2184171440Srrs			}
2185171440Srrs		}
2186171440Srrs	}
2187171440Srrs}
2188171440Srrs
2189217611Stuexenstatic void
2190171440Srrssctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
2191171440Srrs    struct sctp_association *asoc)
2192171440Srrs{
2193171440Srrs	struct sctp_nets *net;
2194171440Srrs
2195171440Srrs	/*
2196216669Stuexen	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
2197171440Srrs	 * (net->fast_retran_loss_recovery == 0)))
2198171440Srrs	 */
2199171440Srrs	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2200211944Stuexen		if ((asoc->fast_retran_loss_recovery == 0) ||
2201216669Stuexen		    (asoc->sctp_cmt_on_off > 0)) {
2202171440Srrs			/* out of a RFC2582 Fast recovery window? */
2203171440Srrs			if (net->net_ack > 0) {
2204171440Srrs				/*
2205171440Srrs				 * per section 7.2.3, are there any
2206171440Srrs				 * destinations that had a fast retransmit
2207171440Srrs				 * to them. If so what we need to do is
2208171440Srrs				 * adjust ssthresh and cwnd.
2209171440Srrs				 */
2210171440Srrs				struct sctp_tmit_chunk *lchk;
2211171440Srrs				int old_cwnd = net->cwnd;
2212171440Srrs
2213171440Srrs				/* JRS - reset as if state were changed */
2214219057Srrs				htcp_reset(&net->cc_mod.htcp_ca);
2215228653Stuexen				net->ssthresh = htcp_recalc_ssthresh(net);
2216171440Srrs				net->cwnd = net->ssthresh;
2217279859Stuexen				sctp_enforce_cwnd_limit(asoc, net);
2218179783Srrs				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2219171440Srrs					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
2220171440Srrs					    SCTP_CWND_LOG_FROM_FR);
2221171440Srrs				}
2222171440Srrs				lchk = TAILQ_FIRST(&asoc->send_queue);
2223171440Srrs
2224171440Srrs				net->partial_bytes_acked = 0;
2225171440Srrs				/* Turn on fast recovery window */
2226171440Srrs				asoc->fast_retran_loss_recovery = 1;
2227171440Srrs				if (lchk == NULL) {
2228171440Srrs					/* Mark end of the window */
2229171440Srrs					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
2230171440Srrs				} else {
2231171440Srrs					asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
2232171440Srrs				}
2233171440Srrs
2234171440Srrs				/*
2235171440Srrs				 * CMT fast recovery -- per destination
2236171440Srrs				 * recovery variable.
2237171440Srrs				 */
2238171440Srrs				net->fast_retran_loss_recovery = 1;
2239171440Srrs
2240171440Srrs				if (lchk == NULL) {
2241171440Srrs					/* Mark end of the window */
2242171440Srrs					net->fast_recovery_tsn = asoc->sending_seq - 1;
2243171440Srrs				} else {
2244171440Srrs					net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
2245171440Srrs				}
2246171440Srrs
2247171440Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
2248283650Stuexen				    stcb->sctp_ep, stcb, net,
2249283650Stuexen				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3);
2250171440Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
2251171440Srrs				    stcb->sctp_ep, stcb, net);
2252171440Srrs			}
2253171440Srrs		} else if (net->net_ack > 0) {
2254171440Srrs			/*
2255171440Srrs			 * Mark a peg that we WOULD have done a cwnd
2256171440Srrs			 * reduction but RFC2582 prevented this action.
2257171440Srrs			 */
2258171440Srrs			SCTP_STAT_INCR(sctps_fastretransinrtt);
2259171440Srrs		}
2260171440Srrs	}
2261171440Srrs}
2262171440Srrs
2263217611Stuexenstatic void
2264171440Srrssctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
2265171440Srrs    struct sctp_nets *net)
2266171440Srrs{
2267171440Srrs	int old_cwnd = net->cwnd;
2268171440Srrs
2269171440Srrs	/* JRS - reset as if the state were being changed to timeout */
2270219057Srrs	htcp_reset(&net->cc_mod.htcp_ca);
2271228653Stuexen	net->ssthresh = htcp_recalc_ssthresh(net);
2272171440Srrs	net->cwnd = net->mtu;
2273179157Srrs	net->partial_bytes_acked = 0;
2274179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2275171440Srrs		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
2276171440Srrs	}
2277171440Srrs}
2278171440Srrs
2279217611Stuexenstatic void
2280171440Srrssctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
2281228653Stuexen    struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED)
2282171440Srrs{
2283171440Srrs	int old_cwnd;
2284171440Srrs
2285171440Srrs	old_cwnd = net->cwnd;
2286171440Srrs
2287171440Srrs	/* JRS - reset hctp as if state changed */
2288218129Srrs	if (in_window == 0) {
2289219057Srrs		htcp_reset(&net->cc_mod.htcp_ca);
2290218129Srrs		SCTP_STAT_INCR(sctps_ecnereducedcwnd);
2291228653Stuexen		net->ssthresh = htcp_recalc_ssthresh(net);
2292218129Srrs		if (net->ssthresh < net->mtu) {
2293218129Srrs			net->ssthresh = net->mtu;
2294218129Srrs			/* here back off the timer as well, to slow us down */
2295218129Srrs			net->RTO <<= 1;
2296218129Srrs		}
2297218129Srrs		net->cwnd = net->ssthresh;
2298279859Stuexen		sctp_enforce_cwnd_limit(&stcb->asoc, net);
2299218129Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2300218129Srrs			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
2301218129Srrs		}
2302171440Srrs	}
2303171440Srrs}
2304217611Stuexen
2305297208Stuexenconst struct sctp_cc_functions sctp_cc_functions[] = {
2306217611Stuexen	{
2307217611Stuexen		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
2308217611Stuexen		.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
2309224641Stuexen		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2310217611Stuexen		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
2311217611Stuexen		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2312217611Stuexen		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
2313217611Stuexen		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2314217611Stuexen		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2315217611Stuexen	},
2316217611Stuexen	{
2317217611Stuexen		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
2318217611Stuexen		.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
2319224641Stuexen		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2320217611Stuexen		.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
2321217611Stuexen		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2322217611Stuexen		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
2323217611Stuexen		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2324217611Stuexen		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2325217611Stuexen	},
2326217611Stuexen	{
2327217611Stuexen		.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
2328217611Stuexen		.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
2329224641Stuexen		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2330217611Stuexen		.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
2331217611Stuexen		.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
2332217611Stuexen		.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
2333217611Stuexen		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2334217611Stuexen		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2335219120Srrs	},
2336219120Srrs	{
2337219120Srrs		.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
2338219120Srrs		.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
2339224641Stuexen		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2340219120Srrs		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
2341219120Srrs		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2342219120Srrs		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
2343219120Srrs		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2344219120Srrs		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2345219120Srrs		.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
2346219120Srrs		.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
2347219120Srrs		.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,
2348219120Srrs		.sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack,
2349219397Srrs		.sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option,
2350219397Srrs		.sctp_rtt_calculated = sctp_rtt_rtcc_calculated
2351217611Stuexen	}
2352217611Stuexen};
2353