sctp_cc_functions.c revision 310219
1/*-
2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * a) Redistributions of source code must retain the above copyright notice,
10 *    this list of conditions and the following disclaimer.
11 *
12 * b) Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in
14 *    the documentation and/or other materials provided with the distribution.
15 *
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its
17 *    contributors may be used to endorse or promote products derived
18 *    from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/11/sys/netinet/sctp_cc_functions.c 310219 2016-12-18 13:04:29Z tuexen $");
35
36#include <netinet/sctp_os.h>
37#include <netinet/sctp_var.h>
38#include <netinet/sctp_sysctl.h>
39#include <netinet/sctp_pcb.h>
40#include <netinet/sctp_header.h>
41#include <netinet/sctputil.h>
42#include <netinet/sctp_output.h>
43#include <netinet/sctp_input.h>
44#include <netinet/sctp_indata.h>
45#include <netinet/sctp_uio.h>
46#include <netinet/sctp_timer.h>
47#include <netinet/sctp_auth.h>
48#include <netinet/sctp_asconf.h>
49#include <netinet/sctp_dtrace_declare.h>
50
51#define SHIFT_MPTCP_MULTI_N 40
52#define SHIFT_MPTCP_MULTI_Z 16
53#define SHIFT_MPTCP_MULTI 8
54
55static void
56sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net)
57{
58	if ((assoc->max_cwnd > 0) &&
59	    (net->cwnd > assoc->max_cwnd) &&
60	    (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
61		net->cwnd = assoc->max_cwnd;
62		if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
63			net->cwnd = net->mtu - sizeof(struct sctphdr);
64		}
65	}
66}
67
68static void
69sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
70{
71	struct sctp_association *assoc;
72	uint32_t cwnd_in_mtu;
73
74	assoc = &stcb->asoc;
75	cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
76	if (cwnd_in_mtu == 0) {
77		/* Using 0 means that the value of RFC 4960 is used. */
78		net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
79	} else {
80		/*
81		 * We take the minimum of the burst limit and the initial
82		 * congestion window.
83		 */
84		if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst))
85			cwnd_in_mtu = assoc->max_burst;
86		net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
87	}
88	if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
89	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) {
90		/* In case of resource pooling initialize appropriately */
91		net->cwnd /= assoc->numnets;
92		if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
93			net->cwnd = net->mtu - sizeof(struct sctphdr);
94		}
95	}
96	sctp_enforce_cwnd_limit(assoc, net);
97	net->ssthresh = assoc->peers_rwnd;
98	SDT_PROBE5(sctp, cwnd, net, init,
99	    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
100	    0, net->cwnd);
101	if (SCTP_BASE_SYSCTL(sctp_logging_level) &
102	    (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
103		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
104	}
105}
106
107static void
108sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
109    struct sctp_association *asoc)
110{
111	struct sctp_nets *net;
112	uint32_t t_ssthresh, t_cwnd;
113	uint64_t t_ucwnd_sbw;
114
115	/* MT FIXME: Don't compute this over and over again */
116	t_ssthresh = 0;
117	t_cwnd = 0;
118	t_ucwnd_sbw = 0;
119	if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) ||
120	    (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) {
121		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
122			t_ssthresh += net->ssthresh;
123			t_cwnd += net->cwnd;
124			if (net->lastsa > 0) {
125				t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) net->lastsa;
126			}
127		}
128		if (t_ucwnd_sbw == 0) {
129			t_ucwnd_sbw = 1;
130		}
131	}
132	/*-
133	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
134	 * (net->fast_retran_loss_recovery == 0)))
135	 */
136	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
137		if ((asoc->fast_retran_loss_recovery == 0) ||
138		    (asoc->sctp_cmt_on_off > 0)) {
139			/* out of a RFC2582 Fast recovery window? */
140			if (net->net_ack > 0) {
141				/*
142				 * per section 7.2.3, are there any
143				 * destinations that had a fast retransmit
144				 * to them. If so what we need to do is
145				 * adjust ssthresh and cwnd.
146				 */
147				struct sctp_tmit_chunk *lchk;
148				int old_cwnd = net->cwnd;
149
150				if ((asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) ||
151				    (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2)) {
152					if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV1) {
153						net->ssthresh = (uint32_t) (((uint64_t) 4 *
154						    (uint64_t) net->mtu *
155						    (uint64_t) net->ssthresh) /
156						    (uint64_t) t_ssthresh);
157
158					}
159					if (asoc->sctp_cmt_on_off == SCTP_CMT_RPV2) {
160						uint32_t srtt;
161
162						srtt = net->lastsa;
163						/* lastsa>>3;  we don't need
164						 * to devide ... */
165						if (srtt == 0) {
166							srtt = 1;
167						}
168						/* Short Version => Equal to
169						 * Contel Version MBe */
170						net->ssthresh = (uint32_t) (((uint64_t) 4 *
171						    (uint64_t) net->mtu *
172						    (uint64_t) net->cwnd) /
173						    ((uint64_t) srtt *
174						    t_ucwnd_sbw));
175						 /* INCREASE FACTOR */ ;
176					}
177					if ((net->cwnd > t_cwnd / 2) &&
178					    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
179						net->ssthresh = net->cwnd - t_cwnd / 2;
180					}
181					if (net->ssthresh < net->mtu) {
182						net->ssthresh = net->mtu;
183					}
184				} else {
185					net->ssthresh = net->cwnd / 2;
186					if (net->ssthresh < (net->mtu * 2)) {
187						net->ssthresh = 2 * net->mtu;
188					}
189				}
190				net->cwnd = net->ssthresh;
191				sctp_enforce_cwnd_limit(asoc, net);
192				SDT_PROBE5(sctp, cwnd, net, fr,
193				    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
194				    old_cwnd, net->cwnd);
195				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
196					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
197					    SCTP_CWND_LOG_FROM_FR);
198				}
199				lchk = TAILQ_FIRST(&asoc->send_queue);
200
201				net->partial_bytes_acked = 0;
202				/* Turn on fast recovery window */
203				asoc->fast_retran_loss_recovery = 1;
204				if (lchk == NULL) {
205					/* Mark end of the window */
206					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
207				} else {
208					asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
209				}
210
211				/*
212				 * CMT fast recovery -- per destination
213				 * recovery variable.
214				 */
215				net->fast_retran_loss_recovery = 1;
216
217				if (lchk == NULL) {
218					/* Mark end of the window */
219					net->fast_recovery_tsn = asoc->sending_seq - 1;
220				} else {
221					net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
222				}
223
224				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
225				    stcb->sctp_ep, stcb, net,
226				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1);
227				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
228				    stcb->sctp_ep, stcb, net);
229			}
230		} else if (net->net_ack > 0) {
231			/*
232			 * Mark a peg that we WOULD have done a cwnd
233			 * reduction but RFC2582 prevented this action.
234			 */
235			SCTP_STAT_INCR(sctps_fastretransinrtt);
236		}
237	}
238}
239
240/* Defines for instantaneous bw decisions */
241#define SCTP_INST_LOOSING 1	/* Losing to other flows */
242#define SCTP_INST_NEUTRAL 2	/* Neutral, no indication */
243#define SCTP_INST_GAINING 3	/* Gaining, step down possible */
244
245
246static int
247cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw,
248    uint64_t rtt_offset, uint64_t vtag, uint8_t inst_ind)
249{
250	uint64_t oth, probepoint;
251
252	probepoint = (((uint64_t) net->cwnd) << 32);
253	if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
254		/*
255		 * rtt increased we don't update bw.. so we don't update the
256		 * rtt either.
257		 */
258		/* Probe point 5 */
259		probepoint |= ((5 << 16) | 1);
260		SDT_PROBE5(sctp, cwnd, net, rttvar,
261		    vtag,
262		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
263		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
264		    net->flight_size,
265		    probepoint);
266		if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) {
267			if (net->cc_mod.rtcc.last_step_state == 5)
268				net->cc_mod.rtcc.step_cnt++;
269			else
270				net->cc_mod.rtcc.step_cnt = 1;
271			net->cc_mod.rtcc.last_step_state = 5;
272			if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) ||
273			    ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
274			    ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
275				/* Try a step down */
276				oth = net->cc_mod.rtcc.vol_reduce;
277				oth <<= 16;
278				oth |= net->cc_mod.rtcc.step_cnt;
279				oth <<= 16;
280				oth |= net->cc_mod.rtcc.last_step_state;
281				SDT_PROBE5(sctp, cwnd, net, rttstep,
282				    vtag,
283				    ((net->cc_mod.rtcc.lbw << 32) | nbw),
284				    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
285				    oth,
286				    probepoint);
287				if (net->cwnd > (4 * net->mtu)) {
288					net->cwnd -= net->mtu;
289					net->cc_mod.rtcc.vol_reduce++;
290				} else {
291					net->cc_mod.rtcc.step_cnt = 0;
292				}
293			}
294		}
295		return (1);
296	}
297	if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
298		/*
299		 * rtt decreased, there could be more room. we update both
300		 * the bw and the rtt here to lock this in as a good step
301		 * down.
302		 */
303		/* Probe point 6 */
304		probepoint |= ((6 << 16) | 0);
305		SDT_PROBE5(sctp, cwnd, net, rttvar,
306		    vtag,
307		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
308		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
309		    net->flight_size,
310		    probepoint);
311		if (net->cc_mod.rtcc.steady_step) {
312			oth = net->cc_mod.rtcc.vol_reduce;
313			oth <<= 16;
314			oth |= net->cc_mod.rtcc.step_cnt;
315			oth <<= 16;
316			oth |= net->cc_mod.rtcc.last_step_state;
317			SDT_PROBE5(sctp, cwnd, net, rttstep,
318			    vtag,
319			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
320			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
321			    oth,
322			    probepoint);
323			if ((net->cc_mod.rtcc.last_step_state == 5) &&
324			    (net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step)) {
325				/* Step down worked */
326				net->cc_mod.rtcc.step_cnt = 0;
327				return (1);
328			} else {
329				net->cc_mod.rtcc.last_step_state = 6;
330				net->cc_mod.rtcc.step_cnt = 0;
331			}
332		}
333		net->cc_mod.rtcc.lbw = nbw;
334		net->cc_mod.rtcc.lbw_rtt = net->rtt;
335		net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
336		if (inst_ind == SCTP_INST_GAINING)
337			return (1);
338		else if (inst_ind == SCTP_INST_NEUTRAL)
339			return (1);
340		else
341			return (0);
342	}
343	/*
344	 * Ok bw and rtt remained the same .. no update to any
345	 */
346	/* Probe point 7 */
347	probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq);
348	SDT_PROBE5(sctp, cwnd, net, rttvar,
349	    vtag,
350	    ((net->cc_mod.rtcc.lbw << 32) | nbw),
351	    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
352	    net->flight_size,
353	    probepoint);
354	if ((net->cc_mod.rtcc.steady_step) && (inst_ind != SCTP_INST_LOOSING)) {
355		if (net->cc_mod.rtcc.last_step_state == 5)
356			net->cc_mod.rtcc.step_cnt++;
357		else
358			net->cc_mod.rtcc.step_cnt = 1;
359		net->cc_mod.rtcc.last_step_state = 5;
360		if ((net->cc_mod.rtcc.step_cnt == net->cc_mod.rtcc.steady_step) ||
361		    ((net->cc_mod.rtcc.step_cnt > net->cc_mod.rtcc.steady_step) &&
362		    ((net->cc_mod.rtcc.step_cnt % net->cc_mod.rtcc.steady_step) == 0))) {
363			/* Try a step down */
364			if (net->cwnd > (4 * net->mtu)) {
365				net->cwnd -= net->mtu;
366				net->cc_mod.rtcc.vol_reduce++;
367				return (1);
368			} else {
369				net->cc_mod.rtcc.step_cnt = 0;
370			}
371		}
372	}
373	if (inst_ind == SCTP_INST_GAINING)
374		return (1);
375	else if (inst_ind == SCTP_INST_NEUTRAL)
376		return (1);
377	else
378		return ((int)net->cc_mod.rtcc.ret_from_eq);
379}
380
381static int
382cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t rtt_offset,
383    uint64_t vtag, uint8_t inst_ind)
384{
385	uint64_t oth, probepoint;
386
387	/* Bandwidth decreased. */
388	probepoint = (((uint64_t) net->cwnd) << 32);
389	if (net->rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
390		/* rtt increased */
391		/* Did we add more */
392		if ((net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) &&
393		    (inst_ind != SCTP_INST_LOOSING)) {
394			/* We caused it maybe.. back off? */
395			/* PROBE POINT 1 */
396			probepoint |= ((1 << 16) | 1);
397			SDT_PROBE5(sctp, cwnd, net, rttvar,
398			    vtag,
399			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
400			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
401			    net->flight_size,
402			    probepoint);
403			if (net->cc_mod.rtcc.ret_from_eq) {
404				/* Switch over to CA if we are less
405				 * aggressive */
406				net->ssthresh = net->cwnd - 1;
407				net->partial_bytes_acked = 0;
408			}
409			return (1);
410		}
411		/* Probe point 2 */
412		probepoint |= ((2 << 16) | 0);
413		SDT_PROBE5(sctp, cwnd, net, rttvar,
414		    vtag,
415		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
416		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
417		    net->flight_size,
418		    probepoint);
419		/* Someone else - fight for more? */
420		if (net->cc_mod.rtcc.steady_step) {
421			oth = net->cc_mod.rtcc.vol_reduce;
422			oth <<= 16;
423			oth |= net->cc_mod.rtcc.step_cnt;
424			oth <<= 16;
425			oth |= net->cc_mod.rtcc.last_step_state;
426			SDT_PROBE5(sctp, cwnd, net, rttstep,
427			    vtag,
428			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
429			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
430			    oth,
431			    probepoint);
432			/*
433			 * Did we voluntarily give up some? if so take one
434			 * back please
435			 */
436			if ((net->cc_mod.rtcc.vol_reduce) &&
437			    (inst_ind != SCTP_INST_GAINING)) {
438				net->cwnd += net->mtu;
439				sctp_enforce_cwnd_limit(&stcb->asoc, net);
440				net->cc_mod.rtcc.vol_reduce--;
441			}
442			net->cc_mod.rtcc.last_step_state = 2;
443			net->cc_mod.rtcc.step_cnt = 0;
444		}
445		goto out_decision;
446	} else if (net->rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
447		/* bw & rtt decreased */
448		/* Probe point 3 */
449		probepoint |= ((3 << 16) | 0);
450		SDT_PROBE5(sctp, cwnd, net, rttvar,
451		    vtag,
452		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
453		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
454		    net->flight_size,
455		    probepoint);
456		if (net->cc_mod.rtcc.steady_step) {
457			oth = net->cc_mod.rtcc.vol_reduce;
458			oth <<= 16;
459			oth |= net->cc_mod.rtcc.step_cnt;
460			oth <<= 16;
461			oth |= net->cc_mod.rtcc.last_step_state;
462			SDT_PROBE5(sctp, cwnd, net, rttstep,
463			    vtag,
464			    ((net->cc_mod.rtcc.lbw << 32) | nbw),
465			    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
466			    oth,
467			    probepoint);
468			if ((net->cc_mod.rtcc.vol_reduce) &&
469			    (inst_ind != SCTP_INST_GAINING)) {
470				net->cwnd += net->mtu;
471				sctp_enforce_cwnd_limit(&stcb->asoc, net);
472				net->cc_mod.rtcc.vol_reduce--;
473			}
474			net->cc_mod.rtcc.last_step_state = 3;
475			net->cc_mod.rtcc.step_cnt = 0;
476		}
477		goto out_decision;
478	}
479	/* The bw decreased but rtt stayed the same */
480	/* Probe point 4 */
481	probepoint |= ((4 << 16) | 0);
482	SDT_PROBE5(sctp, cwnd, net, rttvar,
483	    vtag,
484	    ((net->cc_mod.rtcc.lbw << 32) | nbw),
485	    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
486	    net->flight_size,
487	    probepoint);
488	if (net->cc_mod.rtcc.steady_step) {
489		oth = net->cc_mod.rtcc.vol_reduce;
490		oth <<= 16;
491		oth |= net->cc_mod.rtcc.step_cnt;
492		oth <<= 16;
493		oth |= net->cc_mod.rtcc.last_step_state;
494		SDT_PROBE5(sctp, cwnd, net, rttstep,
495		    vtag,
496		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
497		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
498		    oth,
499		    probepoint);
500		if ((net->cc_mod.rtcc.vol_reduce) &&
501		    (inst_ind != SCTP_INST_GAINING)) {
502			net->cwnd += net->mtu;
503			sctp_enforce_cwnd_limit(&stcb->asoc, net);
504			net->cc_mod.rtcc.vol_reduce--;
505		}
506		net->cc_mod.rtcc.last_step_state = 4;
507		net->cc_mod.rtcc.step_cnt = 0;
508	}
509out_decision:
510	net->cc_mod.rtcc.lbw = nbw;
511	net->cc_mod.rtcc.lbw_rtt = net->rtt;
512	net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
513	if (inst_ind == SCTP_INST_GAINING) {
514		return (1);
515	} else {
516		return (0);
517	}
518}
519
520static int
521cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint64_t vtag)
522{
523	uint64_t oth, probepoint;
524
525	/*
526	 * BW increased, so update and return 0, since all actions in our
527	 * table say to do the normal CC update. Note that we pay no
528	 * attention to the inst_ind since our overall sum is increasing.
529	 */
530	/* PROBE POINT 0 */
531	probepoint = (((uint64_t) net->cwnd) << 32);
532	SDT_PROBE5(sctp, cwnd, net, rttvar,
533	    vtag,
534	    ((net->cc_mod.rtcc.lbw << 32) | nbw),
535	    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
536	    net->flight_size,
537	    probepoint);
538	if (net->cc_mod.rtcc.steady_step) {
539		oth = net->cc_mod.rtcc.vol_reduce;
540		oth <<= 16;
541		oth |= net->cc_mod.rtcc.step_cnt;
542		oth <<= 16;
543		oth |= net->cc_mod.rtcc.last_step_state;
544		SDT_PROBE5(sctp, cwnd, net, rttstep,
545		    vtag,
546		    ((net->cc_mod.rtcc.lbw << 32) | nbw),
547		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
548		    oth,
549		    probepoint);
550		net->cc_mod.rtcc.last_step_state = 0;
551		net->cc_mod.rtcc.step_cnt = 0;
552		net->cc_mod.rtcc.vol_reduce = 0;
553	}
554	net->cc_mod.rtcc.lbw = nbw;
555	net->cc_mod.rtcc.lbw_rtt = net->rtt;
556	net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
557	return (0);
558}
559
560/* RTCC Algorithm to limit growth of cwnd, return
561 * true if you want to NOT allow cwnd growth
562 */
563static int
564cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
565{
566	uint64_t bw_offset, rtt_offset;
567	uint64_t probepoint, rtt, vtag;
568	uint64_t bytes_for_this_rtt, inst_bw;
569	uint64_t div, inst_off;
570	int bw_shift;
571	uint8_t inst_ind;
572	int ret;
573
574	/*-
575	 * Here we need to see if we want
576	 * to limit cwnd growth due to increase
577	 * in overall rtt but no increase in bw.
578	 * We use the following table to figure
579	 * out what we should do. When we return
580	 * 0, cc update goes on as planned. If we
581	 * return 1, then no cc update happens and cwnd
582	 * stays where it is at.
583	 * ----------------------------------
584	 *   BW    |    RTT   | Action
585	 * *********************************
586	 *   INC   |    INC   | return 0
587	 * ----------------------------------
588	 *   INC   |    SAME  | return 0
589	 * ----------------------------------
590	 *   INC   |    DECR  | return 0
591	 * ----------------------------------
592	 *   SAME  |    INC   | return 1
593	 * ----------------------------------
594	 *   SAME  |    SAME  | return 1
595	 * ----------------------------------
596	 *   SAME  |    DECR  | return 0
597	 * ----------------------------------
598	 *   DECR  |    INC   | return 0 or 1 based on if we caused.
599	 * ----------------------------------
600	 *   DECR  |    SAME  | return 0
601	 * ----------------------------------
602	 *   DECR  |    DECR  | return 0
603	 * ----------------------------------
604	 *
605	 * We are a bit fuzz on what an increase or
606	 * decrease is. For BW it is the same if
607	 * it did not change within 1/64th. For
608	 * RTT it stayed the same if it did not
609	 * change within 1/32nd
610	 */
611	bw_shift = SCTP_BASE_SYSCTL(sctp_rttvar_bw);
612	rtt = stcb->asoc.my_vtag;
613	vtag = (rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport);
614	probepoint = (((uint64_t) net->cwnd) << 32);
615	rtt = net->rtt;
616	if (net->cc_mod.rtcc.rtt_set_this_sack) {
617		net->cc_mod.rtcc.rtt_set_this_sack = 0;
618		bytes_for_this_rtt = net->cc_mod.rtcc.bw_bytes - net->cc_mod.rtcc.bw_bytes_at_last_rttc;
619		net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes;
620		if (net->rtt) {
621			div = net->rtt / 1000;
622			if (div) {
623				inst_bw = bytes_for_this_rtt / div;
624				inst_off = inst_bw >> bw_shift;
625				if (inst_bw > nbw)
626					inst_ind = SCTP_INST_GAINING;
627				else if ((inst_bw + inst_off) < nbw)
628					inst_ind = SCTP_INST_LOOSING;
629				else
630					inst_ind = SCTP_INST_NEUTRAL;
631				probepoint |= ((0xb << 16) | inst_ind);
632			} else {
633				inst_ind = net->cc_mod.rtcc.last_inst_ind;
634				inst_bw = bytes_for_this_rtt / (uint64_t) (net->rtt);
635				/* Can't determine do not change */
636				probepoint |= ((0xc << 16) | inst_ind);
637			}
638		} else {
639			inst_ind = net->cc_mod.rtcc.last_inst_ind;
640			inst_bw = bytes_for_this_rtt;
641			/* Can't determine do not change */
642			probepoint |= ((0xd << 16) | inst_ind);
643		}
644		SDT_PROBE5(sctp, cwnd, net, rttvar,
645		    vtag,
646		    ((nbw << 32) | inst_bw),
647		    ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt),
648		    net->flight_size,
649		    probepoint);
650	} else {
651		/* No rtt measurement, use last one */
652		inst_ind = net->cc_mod.rtcc.last_inst_ind;
653	}
654	bw_offset = net->cc_mod.rtcc.lbw >> bw_shift;
655	if (nbw > net->cc_mod.rtcc.lbw + bw_offset) {
656		ret = cc_bw_increase(stcb, net, nbw, vtag);
657		goto out;
658	}
659	rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt);
660	if (nbw < net->cc_mod.rtcc.lbw - bw_offset) {
661		ret = cc_bw_decrease(stcb, net, nbw, rtt_offset, vtag, inst_ind);
662		goto out;
663	}
664	/*
665	 * If we reach here then we are in a situation where the bw stayed
666	 * the same.
667	 */
668	ret = cc_bw_same(stcb, net, nbw, rtt_offset, vtag, inst_ind);
669out:
670	net->cc_mod.rtcc.last_inst_ind = inst_ind;
671	return (ret);
672}
673
674static void
675sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
676    struct sctp_association *asoc,
677    int accum_moved, int reneged_all SCTP_UNUSED, int will_exit, int use_rtcc)
678{
679	struct sctp_nets *net;
680	int old_cwnd;
681	uint32_t t_ssthresh, t_cwnd, incr;
682	uint64_t t_ucwnd_sbw;
683	uint64_t t_path_mptcp;
684	uint64_t mptcp_like_alpha;
685	uint32_t srtt;
686	uint64_t max_path;
687
688	/* MT FIXME: Don't compute this over and over again */
689	t_ssthresh = 0;
690	t_cwnd = 0;
691	t_ucwnd_sbw = 0;
692	t_path_mptcp = 0;
693	mptcp_like_alpha = 1;
694	if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
695	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2) ||
696	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_MPTCP)) {
697		max_path = 0;
698		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
699			t_ssthresh += net->ssthresh;
700			t_cwnd += net->cwnd;
701			/* lastsa>>3;  we don't need to devide ... */
702			srtt = net->lastsa;
703			if (srtt > 0) {
704				uint64_t tmp;
705
706				t_ucwnd_sbw += (uint64_t) net->cwnd / (uint64_t) srtt;
707				t_path_mptcp += (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_Z) /
708				    (((uint64_t) net->mtu) * (uint64_t) srtt);
709				tmp = (((uint64_t) net->cwnd) << SHIFT_MPTCP_MULTI_N) /
710				    ((uint64_t) net->mtu * (uint64_t) (srtt * srtt));
711				if (tmp > max_path) {
712					max_path = tmp;
713				}
714			}
715		}
716		if (t_path_mptcp > 0) {
717			mptcp_like_alpha = max_path / (t_path_mptcp * t_path_mptcp);
718		} else {
719			mptcp_like_alpha = 1;
720		}
721	}
722	if (t_ssthresh == 0) {
723		t_ssthresh = 1;
724	}
725	if (t_ucwnd_sbw == 0) {
726		t_ucwnd_sbw = 1;
727	}
728	/******************************/
729	/* update cwnd and Early FR   */
730	/******************************/
731	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
732
733#ifdef JANA_CMT_FAST_RECOVERY
734		/*
735		 * CMT fast recovery code. Need to debug.
736		 */
737		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
738			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
739			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
740				net->will_exit_fast_recovery = 1;
741			}
742		}
743#endif
744		/* if nothing was acked on this destination skip it */
745		if (net->net_ack == 0) {
746			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
747				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
748			}
749			continue;
750		}
751#ifdef JANA_CMT_FAST_RECOVERY
752		/*
753		 * CMT fast recovery code
754		 */
755		/*
756		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
757		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
758		 * } else if (sctp_cmt_on_off == 0 &&
759		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
760		 */
761#endif
762
763		if (asoc->fast_retran_loss_recovery &&
764		    (will_exit == 0) &&
765		    (asoc->sctp_cmt_on_off == 0)) {
766			/*
767			 * If we are in loss recovery we skip any cwnd
768			 * update
769			 */
770			return;
771		}
772		/*
773		 * Did any measurements go on for this network?
774		 */
775		if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) {
776			uint64_t nbw;
777
778			/*
779			 * At this point our bw_bytes has been updated by
780			 * incoming sack information.
781			 *
782			 * But our bw may not yet be set.
783			 *
784			 */
785			if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) {
786				nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000);
787			} else {
788				nbw = net->cc_mod.rtcc.bw_bytes;
789			}
790			if (net->cc_mod.rtcc.lbw) {
791				if (cc_bw_limit(stcb, net, nbw)) {
792					/* Hold here, no update */
793					continue;
794				}
795			} else {
796				uint64_t vtag, probepoint;
797
798				probepoint = (((uint64_t) net->cwnd) << 32);
799				probepoint |= ((0xa << 16) | 0);
800				vtag = (net->rtt << 32) |
801				    (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
802				    (stcb->rport);
803
804				SDT_PROBE5(sctp, cwnd, net, rttvar,
805				    vtag,
806				    nbw,
807				    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
808				    net->flight_size,
809				    probepoint);
810				net->cc_mod.rtcc.lbw = nbw;
811				net->cc_mod.rtcc.lbw_rtt = net->rtt;
812				if (net->cc_mod.rtcc.rtt_set_this_sack) {
813					net->cc_mod.rtcc.rtt_set_this_sack = 0;
814					net->cc_mod.rtcc.bw_bytes_at_last_rttc = net->cc_mod.rtcc.bw_bytes;
815				}
816			}
817		}
818		/*
819		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
820		 * moved.
821		 */
822		if (accum_moved ||
823		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
824			/* If the cumulative ack moved we can proceed */
825			if (net->cwnd <= net->ssthresh) {
826				/* We are in slow start */
827				if (net->flight_size + net->net_ack >= net->cwnd) {
828					uint32_t limit;
829
830					old_cwnd = net->cwnd;
831					switch (asoc->sctp_cmt_on_off) {
832					case SCTP_CMT_RPV1:
833						limit = (uint32_t) (((uint64_t) net->mtu *
834						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
835						    (uint64_t) net->ssthresh) /
836						    (uint64_t) t_ssthresh);
837						incr = (uint32_t) (((uint64_t) net->net_ack *
838						    (uint64_t) net->ssthresh) /
839						    (uint64_t) t_ssthresh);
840						if (incr > limit) {
841							incr = limit;
842						}
843						if (incr == 0) {
844							incr = 1;
845						}
846						break;
847					case SCTP_CMT_RPV2:
848						/* lastsa>>3;  we don't need
849						 * to divide ... */
850						srtt = net->lastsa;
851						if (srtt == 0) {
852							srtt = 1;
853						}
854						limit = (uint32_t) (((uint64_t) net->mtu *
855						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
856						    (uint64_t) net->cwnd) /
857						    ((uint64_t) srtt * t_ucwnd_sbw));
858						/* INCREASE FACTOR */
859						incr = (uint32_t) (((uint64_t) net->net_ack *
860						    (uint64_t) net->cwnd) /
861						    ((uint64_t) srtt * t_ucwnd_sbw));
862						/* INCREASE FACTOR */
863						if (incr > limit) {
864							incr = limit;
865						}
866						if (incr == 0) {
867							incr = 1;
868						}
869						break;
870					case SCTP_CMT_MPTCP:
871						limit = (uint32_t) (((uint64_t) net->mtu *
872						    mptcp_like_alpha *
873						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) >>
874						    SHIFT_MPTCP_MULTI);
875						incr = (uint32_t) (((uint64_t) net->net_ack *
876						    mptcp_like_alpha) >>
877						    SHIFT_MPTCP_MULTI);
878						if (incr > limit) {
879							incr = limit;
880						}
881						if (incr > net->net_ack) {
882							incr = net->net_ack;
883						}
884						if (incr > net->mtu) {
885							incr = net->mtu;
886						}
887						break;
888					default:
889						incr = net->net_ack;
890						if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) {
891							incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable);
892						}
893						break;
894					}
895					net->cwnd += incr;
896					sctp_enforce_cwnd_limit(asoc, net);
897					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
898						sctp_log_cwnd(stcb, net, incr,
899						    SCTP_CWND_LOG_FROM_SS);
900					}
901					SDT_PROBE5(sctp, cwnd, net, ack,
902					    stcb->asoc.my_vtag,
903					    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
904					    net,
905					    old_cwnd, net->cwnd);
906				} else {
907					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
908						sctp_log_cwnd(stcb, net, net->net_ack,
909						    SCTP_CWND_LOG_NOADV_SS);
910					}
911				}
912			} else {
913				/* We are in congestion avoidance */
914				/*
915				 * Add to pba
916				 */
917				net->partial_bytes_acked += net->net_ack;
918
919				if ((net->flight_size + net->net_ack >= net->cwnd) &&
920				    (net->partial_bytes_acked >= net->cwnd)) {
921					net->partial_bytes_acked -= net->cwnd;
922					old_cwnd = net->cwnd;
923					switch (asoc->sctp_cmt_on_off) {
924					case SCTP_CMT_RPV1:
925						incr = (uint32_t) (((uint64_t) net->mtu *
926						    (uint64_t) net->ssthresh) /
927						    (uint64_t) t_ssthresh);
928						if (incr == 0) {
929							incr = 1;
930						}
931						break;
932					case SCTP_CMT_RPV2:
933						/* lastsa>>3;  we don't need
934						 * to divide ... */
935						srtt = net->lastsa;
936						if (srtt == 0) {
937							srtt = 1;
938						}
939						incr = (uint32_t) ((uint64_t) net->mtu *
940						    (uint64_t) net->cwnd /
941						    ((uint64_t) srtt *
942						    t_ucwnd_sbw));
943						/* INCREASE FACTOR */
944						if (incr == 0) {
945							incr = 1;
946						}
947						break;
948					case SCTP_CMT_MPTCP:
949						incr = (uint32_t) ((mptcp_like_alpha *
950						    (uint64_t) net->cwnd) >>
951						    SHIFT_MPTCP_MULTI);
952						if (incr > net->mtu) {
953							incr = net->mtu;
954						}
955						break;
956					default:
957						incr = net->mtu;
958						break;
959					}
960					net->cwnd += incr;
961					sctp_enforce_cwnd_limit(asoc, net);
962					SDT_PROBE5(sctp, cwnd, net, ack,
963					    stcb->asoc.my_vtag,
964					    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
965					    net,
966					    old_cwnd, net->cwnd);
967					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
968						sctp_log_cwnd(stcb, net, net->mtu,
969						    SCTP_CWND_LOG_FROM_CA);
970					}
971				} else {
972					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
973						sctp_log_cwnd(stcb, net, net->net_ack,
974						    SCTP_CWND_LOG_NOADV_CA);
975					}
976				}
977			}
978		} else {
979			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
980				sctp_log_cwnd(stcb, net, net->mtu,
981				    SCTP_CWND_LOG_NO_CUMACK);
982			}
983		}
984	}
985}
986
987static void
988sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
989{
990	int old_cwnd;
991
992	old_cwnd = net->cwnd;
993	net->cwnd = net->mtu;
994	SDT_PROBE5(sctp, cwnd, net, ack,
995	    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
996	    old_cwnd, net->cwnd);
997	SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
998	    (void *)net, net->cwnd);
999}
1000
1001
1002static void
1003sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
1004{
1005	int old_cwnd = net->cwnd;
1006	uint32_t t_ssthresh, t_cwnd;
1007	uint64_t t_ucwnd_sbw;
1008
1009	/* MT FIXME: Don't compute this over and over again */
1010	t_ssthresh = 0;
1011	t_cwnd = 0;
1012	if ((stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) ||
1013	    (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV2)) {
1014		struct sctp_nets *lnet;
1015		uint32_t srtt;
1016
1017		t_ucwnd_sbw = 0;
1018		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
1019			t_ssthresh += lnet->ssthresh;
1020			t_cwnd += lnet->cwnd;
1021			srtt = lnet->lastsa;
1022			/* lastsa>>3;  we don't need to divide ... */
1023			if (srtt > 0) {
1024				t_ucwnd_sbw += (uint64_t) lnet->cwnd / (uint64_t) srtt;
1025			}
1026		}
1027		if (t_ssthresh < 1) {
1028			t_ssthresh = 1;
1029		}
1030		if (t_ucwnd_sbw < 1) {
1031			t_ucwnd_sbw = 1;
1032		}
1033		if (stcb->asoc.sctp_cmt_on_off == SCTP_CMT_RPV1) {
1034			net->ssthresh = (uint32_t) (((uint64_t) 4 *
1035			    (uint64_t) net->mtu *
1036			    (uint64_t) net->ssthresh) /
1037			    (uint64_t) t_ssthresh);
1038		} else {
1039			uint64_t cc_delta;
1040
1041			srtt = net->lastsa;
1042			/* lastsa>>3;  we don't need to divide ... */
1043			if (srtt == 0) {
1044				srtt = 1;
1045			}
1046			cc_delta = t_ucwnd_sbw * (uint64_t) srtt / 2;
1047			if (cc_delta < t_cwnd) {
1048				net->ssthresh = (uint32_t) ((uint64_t) t_cwnd - cc_delta);
1049			} else {
1050				net->ssthresh = net->mtu;
1051			}
1052		}
1053		if ((net->cwnd > t_cwnd / 2) &&
1054		    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
1055			net->ssthresh = net->cwnd - t_cwnd / 2;
1056		}
1057		if (net->ssthresh < net->mtu) {
1058			net->ssthresh = net->mtu;
1059		}
1060	} else {
1061		net->ssthresh = max(net->cwnd / 2, 4 * net->mtu);
1062	}
1063	net->cwnd = net->mtu;
1064	net->partial_bytes_acked = 0;
1065	SDT_PROBE5(sctp, cwnd, net, to,
1066	    stcb->asoc.my_vtag,
1067	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1068	    net,
1069	    old_cwnd, net->cwnd);
1070	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1071		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
1072	}
1073}
1074
1075static void
1076sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net,
1077    int in_window, int num_pkt_lost, int use_rtcc)
1078{
1079	int old_cwnd = net->cwnd;
1080
1081	if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) {
1082		/* Data center Congestion Control */
1083		if (in_window == 0) {
1084			/*
1085			 * Go to CA with the cwnd at the point we sent the
1086			 * TSN that was marked with a CE.
1087			 */
1088			if (net->ecn_prev_cwnd < net->cwnd) {
1089				/* Restore to prev cwnd */
1090				net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost);
1091			} else {
1092				/* Just cut in 1/2 */
1093				net->cwnd /= 2;
1094			}
1095			/* Drop to CA */
1096			net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu);
1097			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1098				sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1099			}
1100		} else {
1101			/* Further tuning down required over the drastic
1102			 * original cut */
1103			net->ssthresh -= (net->mtu * num_pkt_lost);
1104			net->cwnd -= (net->mtu * num_pkt_lost);
1105			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1106				sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1107			}
1108		}
1109		SCTP_STAT_INCR(sctps_ecnereducedcwnd);
1110	} else {
1111		if (in_window == 0) {
1112			SCTP_STAT_INCR(sctps_ecnereducedcwnd);
1113			net->ssthresh = net->cwnd / 2;
1114			if (net->ssthresh < net->mtu) {
1115				net->ssthresh = net->mtu;
1116				/* here back off the timer as well, to slow
1117				 * us down */
1118				net->RTO <<= 1;
1119			}
1120			net->cwnd = net->ssthresh;
1121			SDT_PROBE5(sctp, cwnd, net, ecn,
1122			    stcb->asoc.my_vtag,
1123			    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1124			    net,
1125			    old_cwnd, net->cwnd);
1126			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1127				sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1128			}
1129		}
1130	}
1131
1132}
1133
1134static void
1135sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
1136    struct sctp_nets *net, struct sctp_pktdrop_chunk *cp,
1137    uint32_t * bottle_bw, uint32_t * on_queue)
1138{
1139	uint32_t bw_avail;
1140	unsigned int incr;
1141	int old_cwnd = net->cwnd;
1142
1143	/* get bottle neck bw */
1144	*bottle_bw = ntohl(cp->bottle_bw);
1145	/* and whats on queue */
1146	*on_queue = ntohl(cp->current_onq);
1147	/*
1148	 * adjust the on-queue if our flight is more it could be that the
1149	 * router has not yet gotten data "in-flight" to it
1150	 */
1151	if (*on_queue < net->flight_size) {
1152		*on_queue = net->flight_size;
1153	}
1154	/* rtt is measured in micro seconds, bottle_bw in bytes per second */
1155	bw_avail = (uint32_t) (((uint64_t) (*bottle_bw) * net->rtt) / (uint64_t) 1000000);
1156	if (bw_avail > *bottle_bw) {
1157		/*
1158		 * Cap the growth to no more than the bottle neck. This can
1159		 * happen as RTT slides up due to queues. It also means if
1160		 * you have more than a 1 second RTT with a empty queue you
1161		 * will be limited to the bottle_bw per second no matter if
1162		 * other points have 1/2 the RTT and you could get more
1163		 * out...
1164		 */
1165		bw_avail = *bottle_bw;
1166	}
1167	if (*on_queue > bw_avail) {
1168		/*
1169		 * No room for anything else don't allow anything else to be
1170		 * "added to the fire".
1171		 */
1172		int seg_inflight, seg_onqueue, my_portion;
1173
1174		net->partial_bytes_acked = 0;
1175		/* how much are we over queue size? */
1176		incr = *on_queue - bw_avail;
1177		if (stcb->asoc.seen_a_sack_this_pkt) {
1178			/*
1179			 * undo any cwnd adjustment that the sack might have
1180			 * made
1181			 */
1182			net->cwnd = net->prev_cwnd;
1183		}
1184		/* Now how much of that is mine? */
1185		seg_inflight = net->flight_size / net->mtu;
1186		seg_onqueue = *on_queue / net->mtu;
1187		my_portion = (incr * seg_inflight) / seg_onqueue;
1188
1189		/* Have I made an adjustment already */
1190		if (net->cwnd > net->flight_size) {
1191			/*
1192			 * for this flight I made an adjustment we need to
1193			 * decrease the portion by a share our previous
1194			 * adjustment.
1195			 */
1196			int diff_adj;
1197
1198			diff_adj = net->cwnd - net->flight_size;
1199			if (diff_adj > my_portion)
1200				my_portion = 0;
1201			else
1202				my_portion -= diff_adj;
1203		}
1204		/*
1205		 * back down to the previous cwnd (assume we have had a sack
1206		 * before this packet). minus what ever portion of the
1207		 * overage is my fault.
1208		 */
1209		net->cwnd -= my_portion;
1210
1211		/* we will NOT back down more than 1 MTU */
1212		if (net->cwnd <= net->mtu) {
1213			net->cwnd = net->mtu;
1214		}
1215		/* force into CA */
1216		net->ssthresh = net->cwnd - 1;
1217	} else {
1218		/*
1219		 * Take 1/4 of the space left or max burst up .. whichever
1220		 * is less.
1221		 */
1222		incr = (bw_avail - *on_queue) >> 2;
1223		if ((stcb->asoc.max_burst > 0) &&
1224		    (stcb->asoc.max_burst * net->mtu < incr)) {
1225			incr = stcb->asoc.max_burst * net->mtu;
1226		}
1227		net->cwnd += incr;
1228	}
1229	if (net->cwnd > bw_avail) {
1230		/* We can't exceed the pipe size */
1231		net->cwnd = bw_avail;
1232	}
1233	if (net->cwnd < net->mtu) {
1234		/* We always have 1 MTU */
1235		net->cwnd = net->mtu;
1236	}
1237	sctp_enforce_cwnd_limit(&stcb->asoc, net);
1238	if (net->cwnd - old_cwnd != 0) {
1239		/* log only changes */
1240		SDT_PROBE5(sctp, cwnd, net, pd,
1241		    stcb->asoc.my_vtag,
1242		    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1243		    net,
1244		    old_cwnd, net->cwnd);
1245		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1246			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
1247			    SCTP_CWND_LOG_FROM_SAT);
1248		}
1249	}
1250}
1251
1252static void
1253sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
1254    struct sctp_nets *net, int burst_limit)
1255{
1256	int old_cwnd = net->cwnd;
1257
1258	if (net->ssthresh < net->cwnd)
1259		net->ssthresh = net->cwnd;
1260	if (burst_limit) {
1261		net->cwnd = (net->flight_size + (burst_limit * net->mtu));
1262		sctp_enforce_cwnd_limit(&stcb->asoc, net);
1263		SDT_PROBE5(sctp, cwnd, net, bl,
1264		    stcb->asoc.my_vtag,
1265		    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
1266		    net,
1267		    old_cwnd, net->cwnd);
1268		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1269			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
1270		}
1271	}
1272}
1273
1274static void
1275sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
1276    struct sctp_association *asoc,
1277    int accum_moved, int reneged_all, int will_exit)
1278{
1279	/* Passing a zero argument in last disables the rtcc algorithm */
1280	sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0);
1281}
1282
1283static void
1284sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
1285    int in_window, int num_pkt_lost)
1286{
1287	/* Passing a zero argument in last disables the rtcc algorithm */
1288	sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0);
1289}
1290
1291/* Here starts the RTCCVAR type CC invented by RRS which
1292 * is a slight mod to RFC2581. We reuse a common routine or
1293 * two since these algorithms are so close and need to
1294 * remain the same.
1295 */
1296static void
1297sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
1298    int in_window, int num_pkt_lost)
1299{
1300	sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1);
1301}
1302
1303
1304static
1305void
1306sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
1307    struct sctp_tmit_chunk *tp1)
1308{
1309	net->cc_mod.rtcc.bw_bytes += tp1->send_size;
1310}
1311
1312static void
1313sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb SCTP_UNUSED,
1314    struct sctp_nets *net)
1315{
1316	if (net->cc_mod.rtcc.tls_needs_set > 0) {
1317		/* We had a bw measurment going on */
1318		struct timeval ltls;
1319
1320		SCTP_GETPTIME_TIMEVAL(&ltls);
1321		timevalsub(&ltls, &net->cc_mod.rtcc.tls);
1322		net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec;
1323	}
1324}
1325
1326static void
1327sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
1328    struct sctp_nets *net)
1329{
1330	uint64_t vtag, probepoint;
1331
1332	if (net->cc_mod.rtcc.lbw) {
1333		/* Clear the old bw.. we went to 0 in-flight */
1334		vtag = (net->rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
1335		    (stcb->rport);
1336		probepoint = (((uint64_t) net->cwnd) << 32);
1337		/* Probe point 8 */
1338		probepoint |= ((8 << 16) | 0);
1339		SDT_PROBE5(sctp, cwnd, net, rttvar,
1340		    vtag,
1341		    ((net->cc_mod.rtcc.lbw << 32) | 0),
1342		    ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt),
1343		    net->flight_size,
1344		    probepoint);
1345		net->cc_mod.rtcc.lbw_rtt = 0;
1346		net->cc_mod.rtcc.cwnd_at_bw_set = 0;
1347		net->cc_mod.rtcc.lbw = 0;
1348		net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0;
1349		net->cc_mod.rtcc.vol_reduce = 0;
1350		net->cc_mod.rtcc.bw_tot_time = 0;
1351		net->cc_mod.rtcc.bw_bytes = 0;
1352		net->cc_mod.rtcc.tls_needs_set = 0;
1353		if (net->cc_mod.rtcc.steady_step) {
1354			net->cc_mod.rtcc.vol_reduce = 0;
1355			net->cc_mod.rtcc.step_cnt = 0;
1356			net->cc_mod.rtcc.last_step_state = 0;
1357		}
1358		if (net->cc_mod.rtcc.ret_from_eq) {
1359			/* less aggressive one - reset cwnd too */
1360			uint32_t cwnd_in_mtu, cwnd;
1361
1362			cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
1363			if (cwnd_in_mtu == 0) {
1364				/* Using 0 means that the value of RFC 4960
1365				 * is used. */
1366				cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
1367			} else {
1368				/*
1369				 * We take the minimum of the burst limit
1370				 * and the initial congestion window.
1371				 */
1372				if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst))
1373					cwnd_in_mtu = stcb->asoc.max_burst;
1374				cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
1375			}
1376			if (net->cwnd > cwnd) {
1377				/* Only set if we are not a timeout (i.e.
1378				 * down to 1 mtu) */
1379				net->cwnd = cwnd;
1380			}
1381		}
1382	}
1383}
1384
1385static void
1386sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
1387    struct sctp_nets *net)
1388{
1389	uint64_t vtag, probepoint;
1390
1391	sctp_set_initial_cc_param(stcb, net);
1392	stcb->asoc.use_precise_time = 1;
1393	probepoint = (((uint64_t) net->cwnd) << 32);
1394	probepoint |= ((9 << 16) | 0);
1395	vtag = (net->rtt << 32) |
1396	    (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
1397	    (stcb->rport);
1398	SDT_PROBE5(sctp, cwnd, net, rttvar,
1399	    vtag,
1400	    0,
1401	    0,
1402	    0,
1403	    probepoint);
1404	net->cc_mod.rtcc.lbw_rtt = 0;
1405	net->cc_mod.rtcc.cwnd_at_bw_set = 0;
1406	net->cc_mod.rtcc.vol_reduce = 0;
1407	net->cc_mod.rtcc.lbw = 0;
1408	net->cc_mod.rtcc.vol_reduce = 0;
1409	net->cc_mod.rtcc.bw_bytes_at_last_rttc = 0;
1410	net->cc_mod.rtcc.bw_tot_time = 0;
1411	net->cc_mod.rtcc.bw_bytes = 0;
1412	net->cc_mod.rtcc.tls_needs_set = 0;
1413	net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret);
1414	net->cc_mod.rtcc.steady_step = SCTP_BASE_SYSCTL(sctp_steady_step);
1415	net->cc_mod.rtcc.use_dccc_ecn = SCTP_BASE_SYSCTL(sctp_use_dccc_ecn);
1416	net->cc_mod.rtcc.step_cnt = 0;
1417	net->cc_mod.rtcc.last_step_state = 0;
1418
1419
1420}
1421
1422static int
1423sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget,
1424    struct sctp_cc_option *cc_opt)
1425{
1426	struct sctp_nets *net;
1427
1428	if (setorget == 1) {
1429		/* a set */
1430		if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
1431			if ((cc_opt->aid_value.assoc_value != 0) &&
1432			    (cc_opt->aid_value.assoc_value != 1)) {
1433				return (EINVAL);
1434			}
1435			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1436				net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value;
1437			}
1438		} else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
1439			if ((cc_opt->aid_value.assoc_value != 0) &&
1440			    (cc_opt->aid_value.assoc_value != 1)) {
1441				return (EINVAL);
1442			}
1443			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1444				net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value;
1445			}
1446		} else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) {
1447			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1448				net->cc_mod.rtcc.steady_step = cc_opt->aid_value.assoc_value;
1449			}
1450		} else {
1451			return (EINVAL);
1452		}
1453	} else {
1454		/* a get */
1455		if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
1456			net = TAILQ_FIRST(&stcb->asoc.nets);
1457			if (net == NULL) {
1458				return (EFAULT);
1459			}
1460			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq;
1461		} else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
1462			net = TAILQ_FIRST(&stcb->asoc.nets);
1463			if (net == NULL) {
1464				return (EFAULT);
1465			}
1466			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn;
1467		} else if (cc_opt->option == SCTP_CC_OPT_STEADY_STEP) {
1468			net = TAILQ_FIRST(&stcb->asoc.nets);
1469			if (net == NULL) {
1470				return (EFAULT);
1471			}
1472			cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.steady_step;
1473		} else {
1474			return (EINVAL);
1475		}
1476	}
1477	return (0);
1478}
1479
1480static void
1481sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb SCTP_UNUSED,
1482    struct sctp_nets *net)
1483{
1484	if (net->cc_mod.rtcc.tls_needs_set == 0) {
1485		SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls);
1486		net->cc_mod.rtcc.tls_needs_set = 2;
1487	}
1488}
1489
1490static void
1491sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb,
1492    struct sctp_association *asoc,
1493    int accum_moved, int reneged_all, int will_exit)
1494{
1495	/* Passing a one argument at the last enables the rtcc algorithm */
1496	sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1);
1497}
1498
1499static void
1500sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED,
1501    struct sctp_nets *net,
1502    struct timeval *now SCTP_UNUSED)
1503{
1504	net->cc_mod.rtcc.rtt_set_this_sack = 1;
1505}
1506
1507/* Here starts Sally Floyds HS-TCP */
1508
1509struct sctp_hs_raise_drop {
1510	int32_t cwnd;
1511	int8_t increase;
1512	int8_t drop_percent;
1513};
1514
1515#define SCTP_HS_TABLE_SIZE 73
1516
1517static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
1518	{38, 1, 50},		/* 0   */
1519	{118, 2, 44},		/* 1   */
1520	{221, 3, 41},		/* 2   */
1521	{347, 4, 38},		/* 3   */
1522	{495, 5, 37},		/* 4   */
1523	{663, 6, 35},		/* 5   */
1524	{851, 7, 34},		/* 6   */
1525	{1058, 8, 33},		/* 7   */
1526	{1284, 9, 32},		/* 8   */
1527	{1529, 10, 31},		/* 9   */
1528	{1793, 11, 30},		/* 10  */
1529	{2076, 12, 29},		/* 11  */
1530	{2378, 13, 28},		/* 12  */
1531	{2699, 14, 28},		/* 13  */
1532	{3039, 15, 27},		/* 14  */
1533	{3399, 16, 27},		/* 15  */
1534	{3778, 17, 26},		/* 16  */
1535	{4177, 18, 26},		/* 17  */
1536	{4596, 19, 25},		/* 18  */
1537	{5036, 20, 25},		/* 19  */
1538	{5497, 21, 24},		/* 20  */
1539	{5979, 22, 24},		/* 21  */
1540	{6483, 23, 23},		/* 22  */
1541	{7009, 24, 23},		/* 23  */
1542	{7558, 25, 22},		/* 24  */
1543	{8130, 26, 22},		/* 25  */
1544	{8726, 27, 22},		/* 26  */
1545	{9346, 28, 21},		/* 27  */
1546	{9991, 29, 21},		/* 28  */
1547	{10661, 30, 21},	/* 29  */
1548	{11358, 31, 20},	/* 30  */
1549	{12082, 32, 20},	/* 31  */
1550	{12834, 33, 20},	/* 32  */
1551	{13614, 34, 19},	/* 33  */
1552	{14424, 35, 19},	/* 34  */
1553	{15265, 36, 19},	/* 35  */
1554	{16137, 37, 19},	/* 36  */
1555	{17042, 38, 18},	/* 37  */
1556	{17981, 39, 18},	/* 38  */
1557	{18955, 40, 18},	/* 39  */
1558	{19965, 41, 17},	/* 40  */
1559	{21013, 42, 17},	/* 41  */
1560	{22101, 43, 17},	/* 42  */
1561	{23230, 44, 17},	/* 43  */
1562	{24402, 45, 16},	/* 44  */
1563	{25618, 46, 16},	/* 45  */
1564	{26881, 47, 16},	/* 46  */
1565	{28193, 48, 16},	/* 47  */
1566	{29557, 49, 15},	/* 48  */
1567	{30975, 50, 15},	/* 49  */
1568	{32450, 51, 15},	/* 50  */
1569	{33986, 52, 15},	/* 51  */
1570	{35586, 53, 14},	/* 52  */
1571	{37253, 54, 14},	/* 53  */
1572	{38992, 55, 14},	/* 54  */
1573	{40808, 56, 14},	/* 55  */
1574	{42707, 57, 13},	/* 56  */
1575	{44694, 58, 13},	/* 57  */
1576	{46776, 59, 13},	/* 58  */
1577	{48961, 60, 13},	/* 59  */
1578	{51258, 61, 13},	/* 60  */
1579	{53677, 62, 12},	/* 61  */
1580	{56230, 63, 12},	/* 62  */
1581	{58932, 64, 12},	/* 63  */
1582	{61799, 65, 12},	/* 64  */
1583	{64851, 66, 11},	/* 65  */
1584	{68113, 67, 11},	/* 66  */
1585	{71617, 68, 11},	/* 67  */
1586	{75401, 69, 10},	/* 68  */
1587	{79517, 70, 10},	/* 69  */
1588	{84035, 71, 10},	/* 70  */
1589	{89053, 72, 10},	/* 71  */
1590	{94717, 73, 9}		/* 72  */
1591};
1592
1593static void
1594sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
1595{
1596	int cur_val, i, indx, incr;
1597	int old_cwnd = net->cwnd;
1598
1599	cur_val = net->cwnd >> 10;
1600	indx = SCTP_HS_TABLE_SIZE - 1;
1601
1602	if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1603		/* normal mode */
1604		if (net->net_ack > net->mtu) {
1605			net->cwnd += net->mtu;
1606		} else {
1607			net->cwnd += net->net_ack;
1608		}
1609	} else {
1610		for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) {
1611			if (cur_val < sctp_cwnd_adjust[i].cwnd) {
1612				indx = i;
1613				break;
1614			}
1615		}
1616		net->last_hs_used = indx;
1617		incr = (((int32_t) sctp_cwnd_adjust[indx].increase) << 10);
1618		net->cwnd += incr;
1619	}
1620	sctp_enforce_cwnd_limit(&stcb->asoc, net);
1621	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1622		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS);
1623	}
1624}
1625
1626static void
1627sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
1628{
1629	int cur_val, i, indx;
1630	int old_cwnd = net->cwnd;
1631
1632	cur_val = net->cwnd >> 10;
1633	if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1634		/* normal mode */
1635		net->ssthresh = net->cwnd / 2;
1636		if (net->ssthresh < (net->mtu * 2)) {
1637			net->ssthresh = 2 * net->mtu;
1638		}
1639		net->cwnd = net->ssthresh;
1640	} else {
1641		/* drop by the proper amount */
1642		net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
1643		    (int32_t) sctp_cwnd_adjust[net->last_hs_used].drop_percent);
1644		net->cwnd = net->ssthresh;
1645		/* now where are we */
1646		indx = net->last_hs_used;
1647		cur_val = net->cwnd >> 10;
1648		/* reset where we are in the table */
1649		if (cur_val < sctp_cwnd_adjust[0].cwnd) {
1650			/* feel out of hs */
1651			net->last_hs_used = 0;
1652		} else {
1653			for (i = indx; i >= 1; i--) {
1654				if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) {
1655					break;
1656				}
1657			}
1658			net->last_hs_used = indx;
1659		}
1660	}
1661	sctp_enforce_cwnd_limit(&stcb->asoc, net);
1662	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1663		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR);
1664	}
1665}
1666
1667static void
1668sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
1669    struct sctp_association *asoc)
1670{
1671	struct sctp_nets *net;
1672
1673	/*
1674	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
1675	 * (net->fast_retran_loss_recovery == 0)))
1676	 */
1677	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1678		if ((asoc->fast_retran_loss_recovery == 0) ||
1679		    (asoc->sctp_cmt_on_off > 0)) {
1680			/* out of a RFC2582 Fast recovery window? */
1681			if (net->net_ack > 0) {
1682				/*
1683				 * per section 7.2.3, are there any
1684				 * destinations that had a fast retransmit
1685				 * to them. If so what we need to do is
1686				 * adjust ssthresh and cwnd.
1687				 */
1688				struct sctp_tmit_chunk *lchk;
1689
1690				sctp_hs_cwnd_decrease(stcb, net);
1691
1692				lchk = TAILQ_FIRST(&asoc->send_queue);
1693
1694				net->partial_bytes_acked = 0;
1695				/* Turn on fast recovery window */
1696				asoc->fast_retran_loss_recovery = 1;
1697				if (lchk == NULL) {
1698					/* Mark end of the window */
1699					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
1700				} else {
1701					asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
1702				}
1703
1704				/*
1705				 * CMT fast recovery -- per destination
1706				 * recovery variable.
1707				 */
1708				net->fast_retran_loss_recovery = 1;
1709
1710				if (lchk == NULL) {
1711					/* Mark end of the window */
1712					net->fast_recovery_tsn = asoc->sending_seq - 1;
1713				} else {
1714					net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
1715				}
1716
1717				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
1718				    stcb->sctp_ep, stcb, net,
1719				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2);
1720				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
1721				    stcb->sctp_ep, stcb, net);
1722			}
1723		} else if (net->net_ack > 0) {
1724			/*
1725			 * Mark a peg that we WOULD have done a cwnd
1726			 * reduction but RFC2582 prevented this action.
1727			 */
1728			SCTP_STAT_INCR(sctps_fastretransinrtt);
1729		}
1730	}
1731}
1732
1733static void
1734sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
1735    struct sctp_association *asoc,
1736    int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
1737{
1738	struct sctp_nets *net;
1739
1740	/******************************/
1741	/* update cwnd and Early FR   */
1742	/******************************/
1743	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1744
1745#ifdef JANA_CMT_FAST_RECOVERY
1746		/*
1747		 * CMT fast recovery code. Need to debug.
1748		 */
1749		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
1750			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
1751			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
1752				net->will_exit_fast_recovery = 1;
1753			}
1754		}
1755#endif
1756		/* if nothing was acked on this destination skip it */
1757		if (net->net_ack == 0) {
1758			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1759				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
1760			}
1761			continue;
1762		}
1763#ifdef JANA_CMT_FAST_RECOVERY
1764		/*
1765		 * CMT fast recovery code
1766		 */
1767		/*
1768		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
1769		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
1770		 * } else if (sctp_cmt_on_off == 0 &&
1771		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
1772		 */
1773#endif
1774
1775		if (asoc->fast_retran_loss_recovery &&
1776		    (will_exit == 0) &&
1777		    (asoc->sctp_cmt_on_off == 0)) {
1778			/*
1779			 * If we are in loss recovery we skip any cwnd
1780			 * update
1781			 */
1782			return;
1783		}
1784		/*
1785		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
1786		 * moved.
1787		 */
1788		if (accum_moved ||
1789		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
1790			/* If the cumulative ack moved we can proceed */
1791			if (net->cwnd <= net->ssthresh) {
1792				/* We are in slow start */
1793				if (net->flight_size + net->net_ack >= net->cwnd) {
1794					sctp_hs_cwnd_increase(stcb, net);
1795				} else {
1796					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1797						sctp_log_cwnd(stcb, net, net->net_ack,
1798						    SCTP_CWND_LOG_NOADV_SS);
1799					}
1800				}
1801			} else {
1802				/* We are in congestion avoidance */
1803				net->partial_bytes_acked += net->net_ack;
1804				if ((net->flight_size + net->net_ack >= net->cwnd) &&
1805				    (net->partial_bytes_acked >= net->cwnd)) {
1806					net->partial_bytes_acked -= net->cwnd;
1807					net->cwnd += net->mtu;
1808					sctp_enforce_cwnd_limit(asoc, net);
1809					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1810						sctp_log_cwnd(stcb, net, net->mtu,
1811						    SCTP_CWND_LOG_FROM_CA);
1812					}
1813				} else {
1814					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1815						sctp_log_cwnd(stcb, net, net->net_ack,
1816						    SCTP_CWND_LOG_NOADV_CA);
1817					}
1818				}
1819			}
1820		} else {
1821			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1822				sctp_log_cwnd(stcb, net, net->mtu,
1823				    SCTP_CWND_LOG_NO_CUMACK);
1824			}
1825		}
1826	}
1827}
1828
1829
1830/*
1831 * H-TCP congestion control. The algorithm is detailed in:
1832 * R.N.Shorten, D.J.Leith:
1833 *   "H-TCP: TCP for high-speed and long-distance networks"
1834 *   Proc. PFLDnet, Argonne, 2004.
1835 * http://www.hamilton.ie/net/htcp3.pdf
1836 */
1837
1838
1839static int use_rtt_scaling = 1;
1840static int use_bandwidth_switch = 1;
1841
1842static inline int
1843between(uint32_t seq1, uint32_t seq2, uint32_t seq3)
1844{
1845	return (seq3 - seq2 >= seq1 - seq2);
1846}
1847
1848static inline uint32_t
1849htcp_cong_time(struct htcp *ca)
1850{
1851	return (sctp_get_tick_count() - ca->last_cong);
1852}
1853
1854static inline uint32_t
1855htcp_ccount(struct htcp *ca)
1856{
1857	return (htcp_cong_time(ca) / ca->minRTT);
1858}
1859
1860static inline void
1861htcp_reset(struct htcp *ca)
1862{
1863	ca->undo_last_cong = ca->last_cong;
1864	ca->undo_maxRTT = ca->maxRTT;
1865	ca->undo_old_maxB = ca->old_maxB;
1866	ca->last_cong = sctp_get_tick_count();
1867}
1868
1869#ifdef SCTP_NOT_USED
1870
1871static uint32_t
1872htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net)
1873{
1874	net->cc_mod.htcp_ca.last_cong = net->cc_mod.htcp_ca.undo_last_cong;
1875	net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.undo_maxRTT;
1876	net->cc_mod.htcp_ca.old_maxB = net->cc_mod.htcp_ca.undo_old_maxB;
1877	return (max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->cc_mod.htcp_ca.beta) * net->mtu));
1878}
1879
1880#endif
1881
1882static inline void
1883measure_rtt(struct sctp_nets *net)
1884{
1885	uint32_t srtt = net->lastsa >> SCTP_RTT_SHIFT;
1886
1887	/* keep track of minimum RTT seen so far, minRTT is zero at first */
1888	if (net->cc_mod.htcp_ca.minRTT > srtt || !net->cc_mod.htcp_ca.minRTT)
1889		net->cc_mod.htcp_ca.minRTT = srtt;
1890
1891	/* max RTT */
1892	if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->cc_mod.htcp_ca) > 3) {
1893		if (net->cc_mod.htcp_ca.maxRTT < net->cc_mod.htcp_ca.minRTT)
1894			net->cc_mod.htcp_ca.maxRTT = net->cc_mod.htcp_ca.minRTT;
1895		if (net->cc_mod.htcp_ca.maxRTT < srtt && srtt <= net->cc_mod.htcp_ca.maxRTT + MSEC_TO_TICKS(20))
1896			net->cc_mod.htcp_ca.maxRTT = srtt;
1897	}
1898}
1899
1900static void
1901measure_achieved_throughput(struct sctp_nets *net)
1902{
1903	uint32_t now = sctp_get_tick_count();
1904
1905	if (net->fast_retran_ip == 0)
1906		net->cc_mod.htcp_ca.bytes_acked = net->net_ack;
1907
1908	if (!use_bandwidth_switch)
1909		return;
1910
1911	/* achieved throughput calculations */
1912	/* JRS - not 100% sure of this statement */
1913	if (net->fast_retran_ip == 1) {
1914		net->cc_mod.htcp_ca.bytecount = 0;
1915		net->cc_mod.htcp_ca.lasttime = now;
1916		return;
1917	}
1918	net->cc_mod.htcp_ca.bytecount += net->net_ack;
1919	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)) &&
1920	    (now - net->cc_mod.htcp_ca.lasttime >= net->cc_mod.htcp_ca.minRTT) &&
1921	    (net->cc_mod.htcp_ca.minRTT > 0)) {
1922		uint32_t cur_Bi = net->cc_mod.htcp_ca.bytecount / net->mtu * hz / (now - net->cc_mod.htcp_ca.lasttime);
1923
1924		if (htcp_ccount(&net->cc_mod.htcp_ca) <= 3) {
1925			/* just after backoff */
1926			net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi = cur_Bi;
1927		} else {
1928			net->cc_mod.htcp_ca.Bi = (3 * net->cc_mod.htcp_ca.Bi + cur_Bi) / 4;
1929			if (net->cc_mod.htcp_ca.Bi > net->cc_mod.htcp_ca.maxB)
1930				net->cc_mod.htcp_ca.maxB = net->cc_mod.htcp_ca.Bi;
1931			if (net->cc_mod.htcp_ca.minB > net->cc_mod.htcp_ca.maxB)
1932				net->cc_mod.htcp_ca.minB = net->cc_mod.htcp_ca.maxB;
1933		}
1934		net->cc_mod.htcp_ca.bytecount = 0;
1935		net->cc_mod.htcp_ca.lasttime = now;
1936	}
1937}
1938
1939static inline void
1940htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT)
1941{
1942	if (use_bandwidth_switch) {
1943		uint32_t maxB = ca->maxB;
1944		uint32_t old_maxB = ca->old_maxB;
1945
1946		ca->old_maxB = ca->maxB;
1947
1948		if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
1949			ca->beta = BETA_MIN;
1950			ca->modeswitch = 0;
1951			return;
1952		}
1953	}
1954	if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) {
1955		ca->beta = (minRTT << 7) / maxRTT;
1956		if (ca->beta < BETA_MIN)
1957			ca->beta = BETA_MIN;
1958		else if (ca->beta > BETA_MAX)
1959			ca->beta = BETA_MAX;
1960	} else {
1961		ca->beta = BETA_MIN;
1962		ca->modeswitch = 1;
1963	}
1964}
1965
1966static inline void
1967htcp_alpha_update(struct htcp *ca)
1968{
1969	uint32_t minRTT = ca->minRTT;
1970	uint32_t factor = 1;
1971	uint32_t diff = htcp_cong_time(ca);
1972
1973	if (diff > (uint32_t) hz) {
1974		diff -= hz;
1975		factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz;
1976	}
1977	if (use_rtt_scaling && minRTT) {
1978		uint32_t scale = (hz << 3) / (10 * minRTT);
1979
1980		scale = min(max(scale, 1U << 2), 10U << 3);	/* clamping ratio to
1981								 * interval [0.5,10]<<3 */
1982		factor = (factor << 3) / scale;
1983		if (!factor)
1984			factor = 1;
1985	}
1986	ca->alpha = 2 * factor * ((1 << 7) - ca->beta);
1987	if (!ca->alpha)
1988		ca->alpha = ALPHA_BASE;
1989}
1990
1991/* After we have the rtt data to calculate beta, we'd still prefer to wait one
1992 * rtt before we adjust our beta to ensure we are working from a consistent
1993 * data.
1994 *
1995 * This function should be called when we hit a congestion event since only at
1996 * that point do we really have a real sense of maxRTT (the queues en route
1997 * were getting just too full now).
1998 */
1999static void
2000htcp_param_update(struct sctp_nets *net)
2001{
2002	uint32_t minRTT = net->cc_mod.htcp_ca.minRTT;
2003	uint32_t maxRTT = net->cc_mod.htcp_ca.maxRTT;
2004
2005	htcp_beta_update(&net->cc_mod.htcp_ca, minRTT, maxRTT);
2006	htcp_alpha_update(&net->cc_mod.htcp_ca);
2007
2008	/* add slowly fading memory for maxRTT to accommodate routing
2009	 * changes etc */
2010	if (minRTT > 0 && maxRTT > minRTT)
2011		net->cc_mod.htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100;
2012}
2013
2014static uint32_t
2015htcp_recalc_ssthresh(struct sctp_nets *net)
2016{
2017	htcp_param_update(net);
2018	return (max(((net->cwnd / net->mtu * net->cc_mod.htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu));
2019}
2020
2021static void
2022htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
2023{
2024	/*-
2025	 * How to handle these functions?
2026         *	if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question.
2027	 *		return;
2028	 */
2029	if (net->cwnd <= net->ssthresh) {
2030		/* We are in slow start */
2031		if (net->flight_size + net->net_ack >= net->cwnd) {
2032			if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) {
2033				net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable));
2034				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2035					sctp_log_cwnd(stcb, net, net->mtu,
2036					    SCTP_CWND_LOG_FROM_SS);
2037				}
2038			} else {
2039				net->cwnd += net->net_ack;
2040				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2041					sctp_log_cwnd(stcb, net, net->net_ack,
2042					    SCTP_CWND_LOG_FROM_SS);
2043				}
2044			}
2045			sctp_enforce_cwnd_limit(&stcb->asoc, net);
2046		} else {
2047			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2048				sctp_log_cwnd(stcb, net, net->net_ack,
2049				    SCTP_CWND_LOG_NOADV_SS);
2050			}
2051		}
2052	} else {
2053		measure_rtt(net);
2054
2055		/*
2056		 * In dangerous area, increase slowly. In theory this is
2057		 * net->cwnd += alpha / net->cwnd
2058		 */
2059		/* What is snd_cwnd_cnt?? */
2060		if (((net->partial_bytes_acked / net->mtu * net->cc_mod.htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) {
2061			/*-
2062			 * Does SCTP have a cwnd clamp?
2063			 * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS).
2064			 */
2065			net->cwnd += net->mtu;
2066			net->partial_bytes_acked = 0;
2067			sctp_enforce_cwnd_limit(&stcb->asoc, net);
2068			htcp_alpha_update(&net->cc_mod.htcp_ca);
2069			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2070				sctp_log_cwnd(stcb, net, net->mtu,
2071				    SCTP_CWND_LOG_FROM_CA);
2072			}
2073		} else {
2074			net->partial_bytes_acked += net->net_ack;
2075			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2076				sctp_log_cwnd(stcb, net, net->net_ack,
2077				    SCTP_CWND_LOG_NOADV_CA);
2078			}
2079		}
2080
2081		net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2082	}
2083}
2084
2085#ifdef SCTP_NOT_USED
2086/* Lower bound on congestion window. */
2087static uint32_t
2088htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net)
2089{
2090	return (net->ssthresh);
2091}
2092#endif
2093
2094static void
2095htcp_init(struct sctp_nets *net)
2096{
2097	memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp));
2098	net->cc_mod.htcp_ca.alpha = ALPHA_BASE;
2099	net->cc_mod.htcp_ca.beta = BETA_MIN;
2100	net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2101	net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
2102}
2103
2104static void
2105sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
2106{
2107	/*
2108	 * We take the max of the burst limit times a MTU or the
2109	 * INITIAL_CWND. We then limit this to 4 MTU's of sending.
2110	 */
2111	net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
2112	net->ssthresh = stcb->asoc.peers_rwnd;
2113	sctp_enforce_cwnd_limit(&stcb->asoc, net);
2114	htcp_init(net);
2115
2116	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
2117		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
2118	}
2119}
2120
2121static void
2122sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
2123    struct sctp_association *asoc,
2124    int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
2125{
2126	struct sctp_nets *net;
2127
2128	/******************************/
2129	/* update cwnd and Early FR   */
2130	/******************************/
2131	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2132
2133#ifdef JANA_CMT_FAST_RECOVERY
2134		/*
2135		 * CMT fast recovery code. Need to debug.
2136		 */
2137		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
2138			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
2139			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
2140				net->will_exit_fast_recovery = 1;
2141			}
2142		}
2143#endif
2144		/* if nothing was acked on this destination skip it */
2145		if (net->net_ack == 0) {
2146			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2147				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
2148			}
2149			continue;
2150		}
2151#ifdef JANA_CMT_FAST_RECOVERY
2152		/*
2153		 * CMT fast recovery code
2154		 */
2155		/*
2156		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
2157		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
2158		 * } else if (sctp_cmt_on_off == 0 &&
2159		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
2160		 */
2161#endif
2162
2163		if (asoc->fast_retran_loss_recovery &&
2164		    will_exit == 0 &&
2165		    (asoc->sctp_cmt_on_off == 0)) {
2166			/*
2167			 * If we are in loss recovery we skip any cwnd
2168			 * update
2169			 */
2170			return;
2171		}
2172		/*
2173		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
2174		 * moved.
2175		 */
2176		if (accum_moved ||
2177		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
2178			htcp_cong_avoid(stcb, net);
2179			measure_achieved_throughput(net);
2180		} else {
2181			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2182				sctp_log_cwnd(stcb, net, net->mtu,
2183				    SCTP_CWND_LOG_NO_CUMACK);
2184			}
2185		}
2186	}
2187}
2188
2189static void
2190sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
2191    struct sctp_association *asoc)
2192{
2193	struct sctp_nets *net;
2194
2195	/*
2196	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
2197	 * (net->fast_retran_loss_recovery == 0)))
2198	 */
2199	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2200		if ((asoc->fast_retran_loss_recovery == 0) ||
2201		    (asoc->sctp_cmt_on_off > 0)) {
2202			/* out of a RFC2582 Fast recovery window? */
2203			if (net->net_ack > 0) {
2204				/*
2205				 * per section 7.2.3, are there any
2206				 * destinations that had a fast retransmit
2207				 * to them. If so what we need to do is
2208				 * adjust ssthresh and cwnd.
2209				 */
2210				struct sctp_tmit_chunk *lchk;
2211				int old_cwnd = net->cwnd;
2212
2213				/* JRS - reset as if state were changed */
2214				htcp_reset(&net->cc_mod.htcp_ca);
2215				net->ssthresh = htcp_recalc_ssthresh(net);
2216				net->cwnd = net->ssthresh;
2217				sctp_enforce_cwnd_limit(asoc, net);
2218				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2219					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
2220					    SCTP_CWND_LOG_FROM_FR);
2221				}
2222				lchk = TAILQ_FIRST(&asoc->send_queue);
2223
2224				net->partial_bytes_acked = 0;
2225				/* Turn on fast recovery window */
2226				asoc->fast_retran_loss_recovery = 1;
2227				if (lchk == NULL) {
2228					/* Mark end of the window */
2229					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
2230				} else {
2231					asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
2232				}
2233
2234				/*
2235				 * CMT fast recovery -- per destination
2236				 * recovery variable.
2237				 */
2238				net->fast_retran_loss_recovery = 1;
2239
2240				if (lchk == NULL) {
2241					/* Mark end of the window */
2242					net->fast_recovery_tsn = asoc->sending_seq - 1;
2243				} else {
2244					net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
2245				}
2246
2247				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
2248				    stcb->sctp_ep, stcb, net,
2249				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3);
2250				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
2251				    stcb->sctp_ep, stcb, net);
2252			}
2253		} else if (net->net_ack > 0) {
2254			/*
2255			 * Mark a peg that we WOULD have done a cwnd
2256			 * reduction but RFC2582 prevented this action.
2257			 */
2258			SCTP_STAT_INCR(sctps_fastretransinrtt);
2259		}
2260	}
2261}
2262
2263static void
2264sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
2265    struct sctp_nets *net)
2266{
2267	int old_cwnd = net->cwnd;
2268
2269	/* JRS - reset as if the state were being changed to timeout */
2270	htcp_reset(&net->cc_mod.htcp_ca);
2271	net->ssthresh = htcp_recalc_ssthresh(net);
2272	net->cwnd = net->mtu;
2273	net->partial_bytes_acked = 0;
2274	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2275		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
2276	}
2277}
2278
2279static void
2280sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
2281    struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED)
2282{
2283	int old_cwnd;
2284
2285	old_cwnd = net->cwnd;
2286
2287	/* JRS - reset hctp as if state changed */
2288	if (in_window == 0) {
2289		htcp_reset(&net->cc_mod.htcp_ca);
2290		SCTP_STAT_INCR(sctps_ecnereducedcwnd);
2291		net->ssthresh = htcp_recalc_ssthresh(net);
2292		if (net->ssthresh < net->mtu) {
2293			net->ssthresh = net->mtu;
2294			/* here back off the timer as well, to slow us down */
2295			net->RTO <<= 1;
2296		}
2297		net->cwnd = net->ssthresh;
2298		sctp_enforce_cwnd_limit(&stcb->asoc, net);
2299		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2300			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
2301		}
2302	}
2303}
2304
2305const struct sctp_cc_functions sctp_cc_functions[] = {
2306	{
2307		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
2308		.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
2309		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2310		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
2311		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2312		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
2313		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2314		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2315	},
2316	{
2317		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
2318		.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
2319		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2320		.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
2321		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2322		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
2323		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2324		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2325	},
2326	{
2327		.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
2328		.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
2329		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2330		.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
2331		.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
2332		.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
2333		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2334		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2335	},
2336	{
2337		.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
2338		.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
2339		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2340		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
2341		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2342		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
2343		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2344		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2345		.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
2346		.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
2347		.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,
2348		.sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack,
2349		.sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option,
2350		.sctp_rtt_calculated = sctp_rtt_rtcc_calculated
2351	}
2352};
2353