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