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