xref: /freebsd/sys/netinet/sctp_cc_functions.c (revision 64a0982bee3db2236df43357e70ce8dddbc21d48)
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 
55 static void
56 sctp_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 
68 static void
69 sctp_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 
107 static void
108 sctp_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 - 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 - 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	/* Losing to other flows */
246 #define SCTP_INST_NEUTRAL 2	/* Neutral, no indication */
247 #define SCTP_INST_GAINING 3	/* Gaining, step down possible */
248 
249 
250 static int
251 cc_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 
385 static int
386 cc_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 	}
515 out_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 
526 static int
527 cc_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 Algorithm to limit growth of cwnd, return
567  * true if you want to NOT allow cwnd growth
568  */
569 static int
570 cc_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);
675 out:
676 	net->cc_mod.rtcc.last_inst_ind = inst_ind;
677 	return (ret);
678 }
679 
680 static void
681 sctp_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 
997 static void
998 sctp_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 
1012 static void
1013 sctp_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 
1085 static void
1086 sctp_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 			 * original 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 
1148 static void
1149 sctp_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 
1266 static void
1267 sctp_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 
1288 static void
1289 sctp_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 algorithm */
1294 	sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0);
1295 }
1296 
1297 static void
1298 sctp_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 algorithm */
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 algorithms are so close and need to
1308  * remain the same.
1309  */
1310 static void
1311 sctp_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 
1318 static
1319 void
1320 sctp_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 
1326 static void
1327 sctp_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 
1340 static void
1341 sctp_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 
1403 static void
1404 sctp_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 
1440 static int
1441 sctp_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 
1498 static void
1499 sctp_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 
1508 static void
1509 sctp_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 algorithm */
1514 	sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1);
1515 }
1516 
1517 static void
1518 sctp_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 
1527 struct sctp_hs_raise_drop {
1528 	int32_t cwnd;
1529 	int8_t increase;
1530 	int8_t drop_percent;
1531 };
1532 
1533 #define SCTP_HS_TABLE_SIZE 73
1534 
1535 static const struct 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 
1611 static void
1612 sctp_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 = (((int32_t)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 
1644 static void
1645 sctp_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 		    (int32_t)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 
1685 static void
1686 sctp_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 - 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 - 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 
1751 static void
1752 sctp_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 
1857 static int use_rtt_scaling = 1;
1858 static int use_bandwidth_switch = 1;
1859 
1860 static inline int
1861 between(uint32_t seq1, uint32_t seq2, uint32_t seq3)
1862 {
1863 	return (seq3 - seq2 >= seq1 - seq2);
1864 }
1865 
1866 static inline uint32_t
1867 htcp_cong_time(struct htcp *ca)
1868 {
1869 	return (sctp_get_tick_count() - ca->last_cong);
1870 }
1871 
1872 static inline uint32_t
1873 htcp_ccount(struct htcp *ca)
1874 {
1875 	return (htcp_cong_time(ca) / ca->minRTT);
1876 }
1877 
1878 static inline void
1879 htcp_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 
1889 static uint32_t
1890 htcp_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 
1900 static inline void
1901 measure_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 
1918 static void
1919 measure_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 
1957 static inline void
1958 htcp_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 
1984 static inline void
1985 htcp_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  */
2017 static void
2018 htcp_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 
2034 static uint32_t
2035 htcp_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 
2041 static void
2042 htcp_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. */
2107 static uint32_t
2108 htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net)
2109 {
2110 	return (net->ssthresh);
2111 }
2112 #endif
2113 
2114 static void
2115 htcp_init(struct sctp_nets *net)
2116 {
2117 	memset(&net->cc_mod.htcp_ca, 0, sizeof(struct htcp));
2118 	net->cc_mod.htcp_ca.alpha = ALPHA_BASE;
2119 	net->cc_mod.htcp_ca.beta = BETA_MIN;
2120 	net->cc_mod.htcp_ca.bytes_acked = net->mtu;
2121 	net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
2122 }
2123 
2124 static void
2125 sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
2126 {
2127 	/*
2128 	 * We take the max of the burst limit times a MTU or the
2129 	 * INITIAL_CWND. We then limit this to 4 MTU's of sending.
2130 	 */
2131 	net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
2132 	net->ssthresh = stcb->asoc.peers_rwnd;
2133 	sctp_enforce_cwnd_limit(&stcb->asoc, net);
2134 	htcp_init(net);
2135 
2136 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
2137 		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
2138 	}
2139 }
2140 
2141 static void
2142 sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
2143     struct sctp_association *asoc,
2144     int accum_moved, int reneged_all SCTP_UNUSED, int will_exit)
2145 {
2146 	struct sctp_nets *net;
2147 
2148 	/******************************/
2149 	/* update cwnd and Early FR   */
2150 	/******************************/
2151 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2152 
2153 #ifdef JANA_CMT_FAST_RECOVERY
2154 		/*
2155 		 * CMT fast recovery code. Need to debug.
2156 		 */
2157 		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
2158 			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
2159 			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
2160 				net->will_exit_fast_recovery = 1;
2161 			}
2162 		}
2163 #endif
2164 		/* if nothing was acked on this destination skip it */
2165 		if (net->net_ack == 0) {
2166 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2167 				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
2168 			}
2169 			continue;
2170 		}
2171 #ifdef JANA_CMT_FAST_RECOVERY
2172 		/*
2173 		 * CMT fast recovery code
2174 		 */
2175 		/*
2176 		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
2177 		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
2178 		 * } else if (sctp_cmt_on_off == 0 &&
2179 		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
2180 		 */
2181 #endif
2182 
2183 		if (asoc->fast_retran_loss_recovery &&
2184 		    will_exit == 0 &&
2185 		    (asoc->sctp_cmt_on_off == 0)) {
2186 			/*
2187 			 * If we are in loss recovery we skip any cwnd
2188 			 * update
2189 			 */
2190 			return;
2191 		}
2192 		/*
2193 		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
2194 		 * moved.
2195 		 */
2196 		if (accum_moved ||
2197 		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
2198 			htcp_cong_avoid(stcb, net);
2199 			measure_achieved_throughput(net);
2200 		} else {
2201 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
2202 				sctp_log_cwnd(stcb, net, net->mtu,
2203 				    SCTP_CWND_LOG_NO_CUMACK);
2204 			}
2205 		}
2206 	}
2207 }
2208 
2209 static void
2210 sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
2211     struct sctp_association *asoc)
2212 {
2213 	struct sctp_nets *net;
2214 
2215 	/*
2216 	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
2217 	 * (net->fast_retran_loss_recovery == 0)))
2218 	 */
2219 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
2220 		if ((asoc->fast_retran_loss_recovery == 0) ||
2221 		    (asoc->sctp_cmt_on_off > 0)) {
2222 			/* out of a RFC2582 Fast recovery window? */
2223 			if (net->net_ack > 0) {
2224 				/*
2225 				 * per section 7.2.3, are there any
2226 				 * destinations that had a fast retransmit
2227 				 * to them. If so what we need to do is
2228 				 * adjust ssthresh and cwnd.
2229 				 */
2230 				struct sctp_tmit_chunk *lchk;
2231 				int old_cwnd = net->cwnd;
2232 
2233 				/* JRS - reset as if state were changed */
2234 				htcp_reset(&net->cc_mod.htcp_ca);
2235 				net->ssthresh = htcp_recalc_ssthresh(net);
2236 				net->cwnd = net->ssthresh;
2237 				sctp_enforce_cwnd_limit(asoc, net);
2238 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2239 					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
2240 					    SCTP_CWND_LOG_FROM_FR);
2241 				}
2242 				lchk = TAILQ_FIRST(&asoc->send_queue);
2243 
2244 				net->partial_bytes_acked = 0;
2245 				/* Turn on fast recovery window */
2246 				asoc->fast_retran_loss_recovery = 1;
2247 				if (lchk == NULL) {
2248 					/* Mark end of the window */
2249 					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
2250 				} else {
2251 					asoc->fast_recovery_tsn = lchk->rec.data.tsn - 1;
2252 				}
2253 
2254 				/*
2255 				 * CMT fast recovery -- per destination
2256 				 * recovery variable.
2257 				 */
2258 				net->fast_retran_loss_recovery = 1;
2259 
2260 				if (lchk == NULL) {
2261 					/* Mark end of the window */
2262 					net->fast_recovery_tsn = asoc->sending_seq - 1;
2263 				} else {
2264 					net->fast_recovery_tsn = lchk->rec.data.tsn - 1;
2265 				}
2266 
2267 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
2268 				    stcb->sctp_ep, stcb, net,
2269 				    SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3);
2270 				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
2271 				    stcb->sctp_ep, stcb, net);
2272 			}
2273 		} else if (net->net_ack > 0) {
2274 			/*
2275 			 * Mark a peg that we WOULD have done a cwnd
2276 			 * reduction but RFC2582 prevented this action.
2277 			 */
2278 			SCTP_STAT_INCR(sctps_fastretransinrtt);
2279 		}
2280 	}
2281 }
2282 
2283 static void
2284 sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
2285     struct sctp_nets *net)
2286 {
2287 	int old_cwnd = net->cwnd;
2288 
2289 	/* JRS - reset as if the state were being changed to timeout */
2290 	htcp_reset(&net->cc_mod.htcp_ca);
2291 	net->ssthresh = htcp_recalc_ssthresh(net);
2292 	net->cwnd = net->mtu;
2293 	net->partial_bytes_acked = 0;
2294 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2295 		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
2296 	}
2297 }
2298 
2299 static void
2300 sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
2301     struct sctp_nets *net, int in_window, int num_pkt_lost SCTP_UNUSED)
2302 {
2303 	int old_cwnd;
2304 
2305 	old_cwnd = net->cwnd;
2306 
2307 	/* JRS - reset hctp as if state changed */
2308 	if (in_window == 0) {
2309 		htcp_reset(&net->cc_mod.htcp_ca);
2310 		SCTP_STAT_INCR(sctps_ecnereducedcwnd);
2311 		net->ssthresh = htcp_recalc_ssthresh(net);
2312 		if (net->ssthresh < net->mtu) {
2313 			net->ssthresh = net->mtu;
2314 			/* here back off the timer as well, to slow us down */
2315 			net->RTO <<= 1;
2316 		}
2317 		net->cwnd = net->ssthresh;
2318 		sctp_enforce_cwnd_limit(&stcb->asoc, net);
2319 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
2320 			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
2321 		}
2322 	}
2323 }
2324 
2325 const struct sctp_cc_functions sctp_cc_functions[] = {
2326 	{
2327 		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
2328 		.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
2329 		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2330 		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
2331 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2332 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
2333 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2334 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2335 	},
2336 	{
2337 		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
2338 		.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
2339 		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2340 		.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
2341 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2342 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
2343 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2344 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2345 	},
2346 	{
2347 		.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
2348 		.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
2349 		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2350 		.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
2351 		.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
2352 		.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
2353 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2354 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2355 	},
2356 	{
2357 		.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
2358 		.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
2359 		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
2360 		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
2361 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
2362 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
2363 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
2364 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
2365 		.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
2366 		.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
2367 		.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,
2368 		.sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack,
2369 		.sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option,
2370 		.sctp_rtt_calculated = sctp_rtt_rtcc_calculated
2371 	}
2372 };
2373