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