xref: /freebsd/sys/netinet/sctp_cc_functions.c (revision 0f27aaf940f2fa5a6540285537b33115a96161a4)
1 /*-
2  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * a) Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  *
10  * b) Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *   the documentation and/or other materials provided with the distribution.
13  *
14  * c) Neither the name of Cisco Systems, Inc. nor the names of its
15  *    contributors may be used to endorse or promote products derived
16  *    from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <netinet/sctp_os.h>
32 #include <netinet/sctp_var.h>
33 #include <netinet/sctp_sysctl.h>
34 #include <netinet/sctp_pcb.h>
35 #include <netinet/sctp_header.h>
36 #include <netinet/sctputil.h>
37 #include <netinet/sctp_output.h>
38 #include <netinet/sctp_input.h>
39 #include <netinet/sctp_indata.h>
40 #include <netinet/sctp_uio.h>
41 #include <netinet/sctp_timer.h>
42 #include <netinet/sctp_auth.h>
43 #include <netinet/sctp_asconf.h>
44 #include <netinet/sctp_dtrace_declare.h>
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47 
48 static void
49 sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
50 {
51 	struct sctp_association *assoc;
52 	uint32_t cwnd_in_mtu;
53 
54 	assoc = &stcb->asoc;
55 	cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
56 	if (cwnd_in_mtu == 0) {
57 		/* Using 0 means that the value of RFC 4960 is used. */
58 		net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
59 	} else {
60 		/*
61 		 * We take the minimum of the burst limit and the initial
62 		 * congestion window.
63 		 */
64 		if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst))
65 			cwnd_in_mtu = assoc->max_burst;
66 		net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
67 	}
68 	if (stcb->asoc.sctp_cmt_on_off == 2) {
69 		/* In case of resource pooling initialize appropriately */
70 		net->cwnd /= assoc->numnets;
71 		if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
72 			net->cwnd = net->mtu - sizeof(struct sctphdr);
73 		}
74 	}
75 	net->ssthresh = assoc->peers_rwnd;
76 
77 	SDT_PROBE(sctp, cwnd, net, init,
78 	    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
79 	    0, net->cwnd);
80 	if (SCTP_BASE_SYSCTL(sctp_logging_level) &
81 	    (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
82 		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
83 	}
84 }
85 
86 static void
87 sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
88     struct sctp_association *asoc)
89 {
90 	struct sctp_nets *net;
91 	uint32_t t_ssthresh, t_cwnd;
92 
93 	/* MT FIXME: Don't compute this over and over again */
94 	t_ssthresh = 0;
95 	t_cwnd = 0;
96 	if (asoc->sctp_cmt_on_off == 2) {
97 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
98 			t_ssthresh += net->ssthresh;
99 			t_cwnd += net->cwnd;
100 		}
101 	}
102 	/*-
103 	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
104 	 * (net->fast_retran_loss_recovery == 0)))
105 	 */
106 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
107 		if ((asoc->fast_retran_loss_recovery == 0) ||
108 		    (asoc->sctp_cmt_on_off > 0)) {
109 			/* out of a RFC2582 Fast recovery window? */
110 			if (net->net_ack > 0) {
111 				/*
112 				 * per section 7.2.3, are there any
113 				 * destinations that had a fast retransmit
114 				 * to them. If so what we need to do is
115 				 * adjust ssthresh and cwnd.
116 				 */
117 				struct sctp_tmit_chunk *lchk;
118 				int old_cwnd = net->cwnd;
119 
120 				if (asoc->sctp_cmt_on_off == 2) {
121 					net->ssthresh = (uint32_t) (((uint64_t) 4 *
122 					    (uint64_t) net->mtu *
123 					    (uint64_t) net->ssthresh) /
124 					    (uint64_t) t_ssthresh);
125 					if ((net->cwnd > t_cwnd / 2) &&
126 					    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
127 						net->ssthresh = net->cwnd - t_cwnd / 2;
128 					}
129 					if (net->ssthresh < net->mtu) {
130 						net->ssthresh = net->mtu;
131 					}
132 				} else {
133 					net->ssthresh = net->cwnd / 2;
134 					if (net->ssthresh < (net->mtu * 2)) {
135 						net->ssthresh = 2 * net->mtu;
136 					}
137 				}
138 				net->cwnd = net->ssthresh;
139 				SDT_PROBE(sctp, cwnd, net, fr,
140 				    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
141 				    old_cwnd, net->cwnd);
142 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
143 					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
144 					    SCTP_CWND_LOG_FROM_FR);
145 				}
146 				lchk = TAILQ_FIRST(&asoc->send_queue);
147 
148 				net->partial_bytes_acked = 0;
149 				/* Turn on fast recovery window */
150 				asoc->fast_retran_loss_recovery = 1;
151 				if (lchk == NULL) {
152 					/* Mark end of the window */
153 					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
154 				} else {
155 					asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
156 				}
157 
158 				/*
159 				 * CMT fast recovery -- per destination
160 				 * recovery variable.
161 				 */
162 				net->fast_retran_loss_recovery = 1;
163 
164 				if (lchk == NULL) {
165 					/* Mark end of the window */
166 					net->fast_recovery_tsn = asoc->sending_seq - 1;
167 				} else {
168 					net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
169 				}
170 
171 				/*
172 				 * Disable Nonce Sum Checking and store the
173 				 * resync tsn
174 				 */
175 				asoc->nonce_sum_check = 0;
176 				asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1;
177 
178 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
179 				    stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
180 				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
181 				    stcb->sctp_ep, stcb, net);
182 			}
183 		} else if (net->net_ack > 0) {
184 			/*
185 			 * Mark a peg that we WOULD have done a cwnd
186 			 * reduction but RFC2582 prevented this action.
187 			 */
188 			SCTP_STAT_INCR(sctps_fastretransinrtt);
189 		}
190 	}
191 }
192 
193 static void
194 sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
195     struct sctp_association *asoc,
196     int accum_moved, int reneged_all, int will_exit)
197 {
198 	struct sctp_nets *net;
199 	int old_cwnd;
200 	uint32_t t_ssthresh, t_cwnd, incr;
201 
202 	/* MT FIXME: Don't compute this over and over again */
203 	t_ssthresh = 0;
204 	t_cwnd = 0;
205 	if (stcb->asoc.sctp_cmt_on_off == 2) {
206 		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
207 			t_ssthresh += net->ssthresh;
208 			t_cwnd += net->cwnd;
209 		}
210 	}
211 	/******************************/
212 	/* update cwnd and Early FR   */
213 	/******************************/
214 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
215 
216 #ifdef JANA_CMT_FAST_RECOVERY
217 		/*
218 		 * CMT fast recovery code. Need to debug.
219 		 */
220 		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
221 			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
222 			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
223 				net->will_exit_fast_recovery = 1;
224 			}
225 		}
226 #endif
227 		if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
228 			/*
229 			 * So, first of all do we need to have a Early FR
230 			 * timer running?
231 			 */
232 			if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
233 			    (net->ref_count > 1) &&
234 			    (net->flight_size < net->cwnd)) ||
235 			    (reneged_all)) {
236 				/*
237 				 * yes, so in this case stop it if its
238 				 * running, and then restart it. Reneging
239 				 * all is a special case where we want to
240 				 * run the Early FR timer and then force the
241 				 * last few unacked to be sent, causing us
242 				 * to illicit a sack with gaps to force out
243 				 * the others.
244 				 */
245 				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
246 					SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
247 					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
248 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
249 				}
250 				SCTP_STAT_INCR(sctps_earlyfrstrid);
251 				sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
252 			} else {
253 				/* No, stop it if its running */
254 				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
255 					SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
256 					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
257 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
258 				}
259 			}
260 		}
261 		/* if nothing was acked on this destination skip it */
262 		if (net->net_ack == 0) {
263 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
264 				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
265 			}
266 			continue;
267 		}
268 		if (net->net_ack2 > 0) {
269 			/*
270 			 * Karn's rule applies to clearing error count, this
271 			 * is optional.
272 			 */
273 			net->error_count = 0;
274 			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
275 			    SCTP_ADDR_NOT_REACHABLE) {
276 				/* addr came good */
277 				net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
278 				net->dest_state |= SCTP_ADDR_REACHABLE;
279 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
280 				    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
281 				/* now was it the primary? if so restore */
282 				if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
283 					(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
284 				}
285 			}
286 			/*
287 			 * JRS 5/14/07 - If CMT PF is on and the destination
288 			 * is in PF state, set the destination to active
289 			 * state and set the cwnd to one or two MTU's based
290 			 * on whether PF1 or PF2 is being used.
291 			 *
292 			 * Should we stop any running T3 timer here?
293 			 */
294 			if ((asoc->sctp_cmt_on_off > 0) &&
295 			    (asoc->sctp_cmt_pf > 0) &&
296 			    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
297 				net->dest_state &= ~SCTP_ADDR_PF;
298 				old_cwnd = net->cwnd;
299 				net->cwnd = net->mtu * asoc->sctp_cmt_pf;
300 				SDT_PROBE(sctp, cwnd, net, ack,
301 				    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
302 				    old_cwnd, net->cwnd);
303 				SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
304 				    net, net->cwnd);
305 				/*
306 				 * Since the cwnd value is explicitly set,
307 				 * skip the code that updates the cwnd
308 				 * value.
309 				 */
310 				goto skip_cwnd_update;
311 			}
312 		}
313 #ifdef JANA_CMT_FAST_RECOVERY
314 		/*
315 		 * CMT fast recovery code
316 		 */
317 		/*
318 		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
319 		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
320 		 * } else if (sctp_cmt_on_off == 0 &&
321 		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
322 		 */
323 #endif
324 
325 		if (asoc->fast_retran_loss_recovery &&
326 		    (will_exit == 0) &&
327 		    (asoc->sctp_cmt_on_off == 0)) {
328 			/*
329 			 * If we are in loss recovery we skip any cwnd
330 			 * update
331 			 */
332 			goto skip_cwnd_update;
333 		}
334 		/*
335 		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
336 		 * moved.
337 		 */
338 		if (accum_moved ||
339 		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
340 			/* If the cumulative ack moved we can proceed */
341 			if (net->cwnd <= net->ssthresh) {
342 				/* We are in slow start */
343 				if (net->flight_size + net->net_ack >= net->cwnd) {
344 					old_cwnd = net->cwnd;
345 					if (stcb->asoc.sctp_cmt_on_off == 2) {
346 						uint32_t limit;
347 
348 						limit = (uint32_t) (((uint64_t) net->mtu *
349 						    (uint64_t) SCTP_BASE_SYSCTL(sctp_L2_abc_variable) *
350 						    (uint64_t) net->ssthresh) /
351 						    (uint64_t) t_ssthresh);
352 						incr = (uint32_t) (((uint64_t) net->net_ack *
353 						    (uint64_t) net->ssthresh) /
354 						    (uint64_t) t_ssthresh);
355 						if (incr > limit) {
356 							incr = limit;
357 						}
358 						if (incr == 0) {
359 							incr = 1;
360 						}
361 					} else {
362 						incr = net->net_ack;
363 						if (incr > net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable)) {
364 							incr = net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable);
365 						}
366 					}
367 					net->cwnd += incr;
368 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
369 						sctp_log_cwnd(stcb, net, incr,
370 						    SCTP_CWND_LOG_FROM_SS);
371 					}
372 					SDT_PROBE(sctp, cwnd, net, ack,
373 					    stcb->asoc.my_vtag,
374 					    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
375 					    net,
376 					    old_cwnd, net->cwnd);
377 				} else {
378 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
379 						sctp_log_cwnd(stcb, net, net->net_ack,
380 						    SCTP_CWND_LOG_NOADV_SS);
381 					}
382 				}
383 			} else {
384 				/* We are in congestion avoidance */
385 				uint32_t incr;
386 
387 				/*
388 				 * Add to pba
389 				 */
390 				net->partial_bytes_acked += net->net_ack;
391 
392 				if ((net->flight_size + net->net_ack >= net->cwnd) &&
393 				    (net->partial_bytes_acked >= net->cwnd)) {
394 					net->partial_bytes_acked -= net->cwnd;
395 					old_cwnd = net->cwnd;
396 					if (asoc->sctp_cmt_on_off == 2) {
397 						incr = (uint32_t) (((uint64_t) net->mtu *
398 						    (uint64_t) net->ssthresh) /
399 						    (uint64_t) t_ssthresh);
400 						if (incr == 0) {
401 							incr = 1;
402 						}
403 					} else {
404 						incr = net->mtu;
405 					}
406 					net->cwnd += incr;
407 					SDT_PROBE(sctp, cwnd, net, ack,
408 					    stcb->asoc.my_vtag,
409 					    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
410 					    net,
411 					    old_cwnd, net->cwnd);
412 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
413 						sctp_log_cwnd(stcb, net, net->mtu,
414 						    SCTP_CWND_LOG_FROM_CA);
415 					}
416 				} else {
417 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
418 						sctp_log_cwnd(stcb, net, net->net_ack,
419 						    SCTP_CWND_LOG_NOADV_CA);
420 					}
421 				}
422 			}
423 		} else {
424 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
425 				sctp_log_cwnd(stcb, net, net->mtu,
426 				    SCTP_CWND_LOG_NO_CUMACK);
427 			}
428 		}
429 skip_cwnd_update:
430 		/*
431 		 * NOW, according to Karn's rule do we need to restore the
432 		 * RTO timer back? Check our net_ack2. If not set then we
433 		 * have a ambiguity.. i.e. all data ack'd was sent to more
434 		 * than one place.
435 		 */
436 		if (net->net_ack2) {
437 			/* restore any doubled timers */
438 			net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1;
439 			if (net->RTO < stcb->asoc.minrto) {
440 				net->RTO = stcb->asoc.minrto;
441 			}
442 			if (net->RTO > stcb->asoc.maxrto) {
443 				net->RTO = stcb->asoc.maxrto;
444 			}
445 		}
446 	}
447 }
448 
449 static void
450 sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
451 {
452 	int old_cwnd = net->cwnd;
453 	uint32_t t_ssthresh, t_cwnd;
454 
455 	/* MT FIXME: Don't compute this over and over again */
456 	t_ssthresh = 0;
457 	t_cwnd = 0;
458 	if (stcb->asoc.sctp_cmt_on_off == 2) {
459 		struct sctp_nets *lnet;
460 
461 		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
462 			t_ssthresh += lnet->ssthresh;
463 			t_cwnd += lnet->cwnd;
464 		}
465 		net->ssthresh = (uint32_t) (((uint64_t) 4 *
466 		    (uint64_t) net->mtu *
467 		    (uint64_t) net->ssthresh) /
468 		    (uint64_t) t_ssthresh);
469 		if ((net->cwnd > t_cwnd / 2) &&
470 		    (net->ssthresh < net->cwnd - t_cwnd / 2)) {
471 			net->ssthresh = net->cwnd - t_cwnd / 2;
472 		}
473 		if (net->ssthresh < net->mtu) {
474 			net->ssthresh = net->mtu;
475 		}
476 	} else {
477 		net->ssthresh = max(net->cwnd / 2, 4 * net->mtu);
478 	}
479 	net->cwnd = net->mtu;
480 	net->partial_bytes_acked = 0;
481 	SDT_PROBE(sctp, cwnd, net, to,
482 	    stcb->asoc.my_vtag,
483 	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
484 	    net,
485 	    old_cwnd, net->cwnd);
486 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
487 		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
488 	}
489 }
490 
491 static void
492 sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net)
493 {
494 	int old_cwnd = net->cwnd;
495 
496 	SCTP_STAT_INCR(sctps_ecnereducedcwnd);
497 	net->ssthresh = net->cwnd / 2;
498 	if (net->ssthresh < net->mtu) {
499 		net->ssthresh = net->mtu;
500 		/* here back off the timer as well, to slow us down */
501 		net->RTO <<= 1;
502 	}
503 	net->cwnd = net->ssthresh;
504 	SDT_PROBE(sctp, cwnd, net, ecn,
505 	    stcb->asoc.my_vtag,
506 	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
507 	    net,
508 	    old_cwnd, net->cwnd);
509 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
510 		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
511 	}
512 }
513 
514 static void
515 sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
516     struct sctp_nets *net, struct sctp_pktdrop_chunk *cp,
517     uint32_t * bottle_bw, uint32_t * on_queue)
518 {
519 	uint32_t bw_avail;
520 	int rtt, incr;
521 	int old_cwnd = net->cwnd;
522 
523 	/* need real RTT for this calc */
524 	rtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
525 	/* get bottle neck bw */
526 	*bottle_bw = ntohl(cp->bottle_bw);
527 	/* and whats on queue */
528 	*on_queue = ntohl(cp->current_onq);
529 	/*
530 	 * adjust the on-queue if our flight is more it could be that the
531 	 * router has not yet gotten data "in-flight" to it
532 	 */
533 	if (*on_queue < net->flight_size)
534 		*on_queue = net->flight_size;
535 	/* calculate the available space */
536 	bw_avail = (*bottle_bw * rtt) / 1000;
537 	if (bw_avail > *bottle_bw) {
538 		/*
539 		 * Cap the growth to no more than the bottle neck. This can
540 		 * happen as RTT slides up due to queues. It also means if
541 		 * you have more than a 1 second RTT with a empty queue you
542 		 * will be limited to the bottle_bw per second no matter if
543 		 * other points have 1/2 the RTT and you could get more
544 		 * out...
545 		 */
546 		bw_avail = *bottle_bw;
547 	}
548 	if (*on_queue > bw_avail) {
549 		/*
550 		 * No room for anything else don't allow anything else to be
551 		 * "added to the fire".
552 		 */
553 		int seg_inflight, seg_onqueue, my_portion;
554 
555 		net->partial_bytes_acked = 0;
556 
557 		/* how much are we over queue size? */
558 		incr = *on_queue - bw_avail;
559 		if (stcb->asoc.seen_a_sack_this_pkt) {
560 			/*
561 			 * undo any cwnd adjustment that the sack might have
562 			 * made
563 			 */
564 			net->cwnd = net->prev_cwnd;
565 		}
566 		/* Now how much of that is mine? */
567 		seg_inflight = net->flight_size / net->mtu;
568 		seg_onqueue = *on_queue / net->mtu;
569 		my_portion = (incr * seg_inflight) / seg_onqueue;
570 
571 		/* Have I made an adjustment already */
572 		if (net->cwnd > net->flight_size) {
573 			/*
574 			 * for this flight I made an adjustment we need to
575 			 * decrease the portion by a share our previous
576 			 * adjustment.
577 			 */
578 			int diff_adj;
579 
580 			diff_adj = net->cwnd - net->flight_size;
581 			if (diff_adj > my_portion)
582 				my_portion = 0;
583 			else
584 				my_portion -= diff_adj;
585 		}
586 		/*
587 		 * back down to the previous cwnd (assume we have had a sack
588 		 * before this packet). minus what ever portion of the
589 		 * overage is my fault.
590 		 */
591 		net->cwnd -= my_portion;
592 
593 		/* we will NOT back down more than 1 MTU */
594 		if (net->cwnd <= net->mtu) {
595 			net->cwnd = net->mtu;
596 		}
597 		/* force into CA */
598 		net->ssthresh = net->cwnd - 1;
599 	} else {
600 		/*
601 		 * Take 1/4 of the space left or max burst up .. whichever
602 		 * is less.
603 		 */
604 		incr = (bw_avail - *on_queue) >> 2;
605 		if ((stcb->asoc.max_burst > 0) &&
606 		    (stcb->asoc.max_burst * net->mtu < incr)) {
607 			incr = stcb->asoc.max_burst * net->mtu;
608 		}
609 		net->cwnd += incr;
610 	}
611 	if (net->cwnd > bw_avail) {
612 		/* We can't exceed the pipe size */
613 		net->cwnd = bw_avail;
614 	}
615 	if (net->cwnd < net->mtu) {
616 		/* We always have 1 MTU */
617 		net->cwnd = net->mtu;
618 	}
619 	if (net->cwnd - old_cwnd != 0) {
620 		/* log only changes */
621 		SDT_PROBE(sctp, cwnd, net, pd,
622 		    stcb->asoc.my_vtag,
623 		    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
624 		    net,
625 		    old_cwnd, net->cwnd);
626 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
627 			sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
628 			    SCTP_CWND_LOG_FROM_SAT);
629 		}
630 	}
631 }
632 
633 static void
634 sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
635     struct sctp_nets *net, int burst_limit)
636 {
637 	int old_cwnd = net->cwnd;
638 
639 	if (net->ssthresh < net->cwnd)
640 		net->ssthresh = net->cwnd;
641 	net->cwnd = (net->flight_size + (burst_limit * net->mtu));
642 	SDT_PROBE(sctp, cwnd, net, bl,
643 	    stcb->asoc.my_vtag,
644 	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
645 	    net,
646 	    old_cwnd, net->cwnd);
647 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
648 		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
649 	}
650 }
651 
652 static void
653 sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
654     struct sctp_tcb *stcb, struct sctp_nets *net)
655 {
656 	int old_cwnd = net->cwnd;
657 
658 	sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
659 	/*
660 	 * make a small adjustment to cwnd and force to CA.
661 	 */
662 	if (net->cwnd > net->mtu)
663 		/* drop down one MTU after sending */
664 		net->cwnd -= net->mtu;
665 	if (net->cwnd < net->ssthresh)
666 		/* still in SS move to CA */
667 		net->ssthresh = net->cwnd - 1;
668 	SDT_PROBE(sctp, cwnd, net, fr,
669 	    stcb->asoc.my_vtag,
670 	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
671 	    net,
672 	    old_cwnd, net->cwnd);
673 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
674 		sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
675 	}
676 }
677 
678 struct sctp_hs_raise_drop {
679 	int32_t cwnd;
680 	int32_t increase;
681 	int32_t drop_percent;
682 };
683 
684 #define SCTP_HS_TABLE_SIZE 73
685 
686 struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
687 	{38, 1, 50},		/* 0   */
688 	{118, 2, 44},		/* 1   */
689 	{221, 3, 41},		/* 2   */
690 	{347, 4, 38},		/* 3   */
691 	{495, 5, 37},		/* 4   */
692 	{663, 6, 35},		/* 5   */
693 	{851, 7, 34},		/* 6   */
694 	{1058, 8, 33},		/* 7   */
695 	{1284, 9, 32},		/* 8   */
696 	{1529, 10, 31},		/* 9   */
697 	{1793, 11, 30},		/* 10  */
698 	{2076, 12, 29},		/* 11  */
699 	{2378, 13, 28},		/* 12  */
700 	{2699, 14, 28},		/* 13  */
701 	{3039, 15, 27},		/* 14  */
702 	{3399, 16, 27},		/* 15  */
703 	{3778, 17, 26},		/* 16  */
704 	{4177, 18, 26},		/* 17  */
705 	{4596, 19, 25},		/* 18  */
706 	{5036, 20, 25},		/* 19  */
707 	{5497, 21, 24},		/* 20  */
708 	{5979, 22, 24},		/* 21  */
709 	{6483, 23, 23},		/* 22  */
710 	{7009, 24, 23},		/* 23  */
711 	{7558, 25, 22},		/* 24  */
712 	{8130, 26, 22},		/* 25  */
713 	{8726, 27, 22},		/* 26  */
714 	{9346, 28, 21},		/* 27  */
715 	{9991, 29, 21},		/* 28  */
716 	{10661, 30, 21},	/* 29  */
717 	{11358, 31, 20},	/* 30  */
718 	{12082, 32, 20},	/* 31  */
719 	{12834, 33, 20},	/* 32  */
720 	{13614, 34, 19},	/* 33  */
721 	{14424, 35, 19},	/* 34  */
722 	{15265, 36, 19},	/* 35  */
723 	{16137, 37, 19},	/* 36  */
724 	{17042, 38, 18},	/* 37  */
725 	{17981, 39, 18},	/* 38  */
726 	{18955, 40, 18},	/* 39  */
727 	{19965, 41, 17},	/* 40  */
728 	{21013, 42, 17},	/* 41  */
729 	{22101, 43, 17},	/* 42  */
730 	{23230, 44, 17},	/* 43  */
731 	{24402, 45, 16},	/* 44  */
732 	{25618, 46, 16},	/* 45  */
733 	{26881, 47, 16},	/* 46  */
734 	{28193, 48, 16},	/* 47  */
735 	{29557, 49, 15},	/* 48  */
736 	{30975, 50, 15},	/* 49  */
737 	{32450, 51, 15},	/* 50  */
738 	{33986, 52, 15},	/* 51  */
739 	{35586, 53, 14},	/* 52  */
740 	{37253, 54, 14},	/* 53  */
741 	{38992, 55, 14},	/* 54  */
742 	{40808, 56, 14},	/* 55  */
743 	{42707, 57, 13},	/* 56  */
744 	{44694, 58, 13},	/* 57  */
745 	{46776, 59, 13},	/* 58  */
746 	{48961, 60, 13},	/* 59  */
747 	{51258, 61, 13},	/* 60  */
748 	{53677, 62, 12},	/* 61  */
749 	{56230, 63, 12},	/* 62  */
750 	{58932, 64, 12},	/* 63  */
751 	{61799, 65, 12},	/* 64  */
752 	{64851, 66, 11},	/* 65  */
753 	{68113, 67, 11},	/* 66  */
754 	{71617, 68, 11},	/* 67  */
755 	{75401, 69, 10},	/* 68  */
756 	{79517, 70, 10},	/* 69  */
757 	{84035, 71, 10},	/* 70  */
758 	{89053, 72, 10},	/* 71  */
759 	{94717, 73, 9}		/* 72  */
760 };
761 
762 static void
763 sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
764 {
765 	int cur_val, i, indx, incr;
766 
767 	cur_val = net->cwnd >> 10;
768 	indx = SCTP_HS_TABLE_SIZE - 1;
769 #ifdef SCTP_DEBUG
770 	printf("HS CC CAlled.\n");
771 #endif
772 	if (cur_val < sctp_cwnd_adjust[0].cwnd) {
773 		/* normal mode */
774 		if (net->net_ack > net->mtu) {
775 			net->cwnd += net->mtu;
776 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
777 				sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS);
778 			}
779 		} else {
780 			net->cwnd += net->net_ack;
781 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
782 				sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS);
783 			}
784 		}
785 	} else {
786 		for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) {
787 			if (cur_val < sctp_cwnd_adjust[i].cwnd) {
788 				indx = i;
789 				break;
790 			}
791 		}
792 		net->last_hs_used = indx;
793 		incr = ((sctp_cwnd_adjust[indx].increase) << 10);
794 		net->cwnd += incr;
795 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
796 			sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS);
797 		}
798 	}
799 }
800 
801 static void
802 sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
803 {
804 	int cur_val, i, indx;
805 	int old_cwnd = net->cwnd;
806 
807 	cur_val = net->cwnd >> 10;
808 	if (cur_val < sctp_cwnd_adjust[0].cwnd) {
809 		/* normal mode */
810 		net->ssthresh = net->cwnd / 2;
811 		if (net->ssthresh < (net->mtu * 2)) {
812 			net->ssthresh = 2 * net->mtu;
813 		}
814 		net->cwnd = net->ssthresh;
815 	} else {
816 		/* drop by the proper amount */
817 		net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
818 		    sctp_cwnd_adjust[net->last_hs_used].drop_percent);
819 		net->cwnd = net->ssthresh;
820 		/* now where are we */
821 		indx = net->last_hs_used;
822 		cur_val = net->cwnd >> 10;
823 		/* reset where we are in the table */
824 		if (cur_val < sctp_cwnd_adjust[0].cwnd) {
825 			/* feel out of hs */
826 			net->last_hs_used = 0;
827 		} else {
828 			for (i = indx; i >= 1; i--) {
829 				if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) {
830 					break;
831 				}
832 			}
833 			net->last_hs_used = indx;
834 		}
835 	}
836 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
837 		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR);
838 	}
839 }
840 
841 static void
842 sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb,
843     struct sctp_association *asoc)
844 {
845 	struct sctp_nets *net;
846 
847 	/*
848 	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
849 	 * (net->fast_retran_loss_recovery == 0)))
850 	 */
851 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
852 		if ((asoc->fast_retran_loss_recovery == 0) ||
853 		    (asoc->sctp_cmt_on_off > 0)) {
854 			/* out of a RFC2582 Fast recovery window? */
855 			if (net->net_ack > 0) {
856 				/*
857 				 * per section 7.2.3, are there any
858 				 * destinations that had a fast retransmit
859 				 * to them. If so what we need to do is
860 				 * adjust ssthresh and cwnd.
861 				 */
862 				struct sctp_tmit_chunk *lchk;
863 
864 				sctp_hs_cwnd_decrease(stcb, net);
865 
866 				lchk = TAILQ_FIRST(&asoc->send_queue);
867 
868 				net->partial_bytes_acked = 0;
869 				/* Turn on fast recovery window */
870 				asoc->fast_retran_loss_recovery = 1;
871 				if (lchk == NULL) {
872 					/* Mark end of the window */
873 					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
874 				} else {
875 					asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
876 				}
877 
878 				/*
879 				 * CMT fast recovery -- per destination
880 				 * recovery variable.
881 				 */
882 				net->fast_retran_loss_recovery = 1;
883 
884 				if (lchk == NULL) {
885 					/* Mark end of the window */
886 					net->fast_recovery_tsn = asoc->sending_seq - 1;
887 				} else {
888 					net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
889 				}
890 
891 				/*
892 				 * Disable Nonce Sum Checking and store the
893 				 * resync tsn
894 				 */
895 				asoc->nonce_sum_check = 0;
896 				asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1;
897 
898 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
899 				    stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
900 				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
901 				    stcb->sctp_ep, stcb, net);
902 			}
903 		} else if (net->net_ack > 0) {
904 			/*
905 			 * Mark a peg that we WOULD have done a cwnd
906 			 * reduction but RFC2582 prevented this action.
907 			 */
908 			SCTP_STAT_INCR(sctps_fastretransinrtt);
909 		}
910 	}
911 }
912 
913 static void
914 sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
915     struct sctp_association *asoc,
916     int accum_moved, int reneged_all, int will_exit)
917 {
918 	struct sctp_nets *net;
919 
920 	/******************************/
921 	/* update cwnd and Early FR   */
922 	/******************************/
923 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
924 
925 #ifdef JANA_CMT_FAST_RECOVERY
926 		/*
927 		 * CMT fast recovery code. Need to debug.
928 		 */
929 		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
930 			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
931 			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
932 				net->will_exit_fast_recovery = 1;
933 			}
934 		}
935 #endif
936 		if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
937 			/*
938 			 * So, first of all do we need to have a Early FR
939 			 * timer running?
940 			 */
941 			if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
942 			    (net->ref_count > 1) &&
943 			    (net->flight_size < net->cwnd)) ||
944 			    (reneged_all)) {
945 				/*
946 				 * yes, so in this case stop it if its
947 				 * running, and then restart it. Reneging
948 				 * all is a special case where we want to
949 				 * run the Early FR timer and then force the
950 				 * last few unacked to be sent, causing us
951 				 * to illicit a sack with gaps to force out
952 				 * the others.
953 				 */
954 				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
955 					SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
956 					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
957 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
958 				}
959 				SCTP_STAT_INCR(sctps_earlyfrstrid);
960 				sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
961 			} else {
962 				/* No, stop it if its running */
963 				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
964 					SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
965 					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
966 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
967 				}
968 			}
969 		}
970 		/* if nothing was acked on this destination skip it */
971 		if (net->net_ack == 0) {
972 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
973 				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
974 			}
975 			continue;
976 		}
977 		if (net->net_ack2 > 0) {
978 			/*
979 			 * Karn's rule applies to clearing error count, this
980 			 * is optional.
981 			 */
982 			net->error_count = 0;
983 			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
984 			    SCTP_ADDR_NOT_REACHABLE) {
985 				/* addr came good */
986 				net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
987 				net->dest_state |= SCTP_ADDR_REACHABLE;
988 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
989 				    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
990 				/* now was it the primary? if so restore */
991 				if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
992 					(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
993 				}
994 			}
995 			/*
996 			 * JRS 5/14/07 - If CMT PF is on and the destination
997 			 * is in PF state, set the destination to active
998 			 * state and set the cwnd to one or two MTU's based
999 			 * on whether PF1 or PF2 is being used.
1000 			 *
1001 			 * Should we stop any running T3 timer here?
1002 			 */
1003 			if ((asoc->sctp_cmt_on_off > 0) &&
1004 			    (asoc->sctp_cmt_pf > 0) &&
1005 			    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
1006 				net->dest_state &= ~SCTP_ADDR_PF;
1007 				net->cwnd = net->mtu * asoc->sctp_cmt_pf;
1008 				SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
1009 				    net, net->cwnd);
1010 				/*
1011 				 * Since the cwnd value is explicitly set,
1012 				 * skip the code that updates the cwnd
1013 				 * value.
1014 				 */
1015 				goto skip_cwnd_update;
1016 			}
1017 		}
1018 #ifdef JANA_CMT_FAST_RECOVERY
1019 		/*
1020 		 * CMT fast recovery code
1021 		 */
1022 		/*
1023 		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
1024 		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
1025 		 * } else if (sctp_cmt_on_off == 0 &&
1026 		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
1027 		 */
1028 #endif
1029 
1030 		if (asoc->fast_retran_loss_recovery &&
1031 		    (will_exit == 0) &&
1032 		    (asoc->sctp_cmt_on_off == 0)) {
1033 			/*
1034 			 * If we are in loss recovery we skip any cwnd
1035 			 * update
1036 			 */
1037 			goto skip_cwnd_update;
1038 		}
1039 		/*
1040 		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
1041 		 * moved.
1042 		 */
1043 		if (accum_moved ||
1044 		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
1045 			/* If the cumulative ack moved we can proceed */
1046 			if (net->cwnd <= net->ssthresh) {
1047 				/* We are in slow start */
1048 				if (net->flight_size + net->net_ack >= net->cwnd) {
1049 
1050 					sctp_hs_cwnd_increase(stcb, net);
1051 
1052 				} else {
1053 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1054 						sctp_log_cwnd(stcb, net, net->net_ack,
1055 						    SCTP_CWND_LOG_NOADV_SS);
1056 					}
1057 				}
1058 			} else {
1059 				/* We are in congestion avoidance */
1060 				net->partial_bytes_acked += net->net_ack;
1061 				if ((net->flight_size + net->net_ack >= net->cwnd) &&
1062 				    (net->partial_bytes_acked >= net->cwnd)) {
1063 					net->partial_bytes_acked -= net->cwnd;
1064 					net->cwnd += net->mtu;
1065 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1066 						sctp_log_cwnd(stcb, net, net->mtu,
1067 						    SCTP_CWND_LOG_FROM_CA);
1068 					}
1069 				} else {
1070 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1071 						sctp_log_cwnd(stcb, net, net->net_ack,
1072 						    SCTP_CWND_LOG_NOADV_CA);
1073 					}
1074 				}
1075 			}
1076 		} else {
1077 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1078 				sctp_log_cwnd(stcb, net, net->mtu,
1079 				    SCTP_CWND_LOG_NO_CUMACK);
1080 			}
1081 		}
1082 skip_cwnd_update:
1083 		/*
1084 		 * NOW, according to Karn's rule do we need to restore the
1085 		 * RTO timer back? Check our net_ack2. If not set then we
1086 		 * have a ambiguity.. i.e. all data ack'd was sent to more
1087 		 * than one place.
1088 		 */
1089 		if (net->net_ack2) {
1090 			/* restore any doubled timers */
1091 			net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1;
1092 			if (net->RTO < stcb->asoc.minrto) {
1093 				net->RTO = stcb->asoc.minrto;
1094 			}
1095 			if (net->RTO > stcb->asoc.maxrto) {
1096 				net->RTO = stcb->asoc.maxrto;
1097 			}
1098 		}
1099 	}
1100 }
1101 
1102 
1103 /*
1104  * H-TCP congestion control. The algorithm is detailed in:
1105  * R.N.Shorten, D.J.Leith:
1106  *   "H-TCP: TCP for high-speed and long-distance networks"
1107  *   Proc. PFLDnet, Argonne, 2004.
1108  * http://www.hamilton.ie/net/htcp3.pdf
1109  */
1110 
1111 
1112 static int use_rtt_scaling = 1;
1113 static int use_bandwidth_switch = 1;
1114 
1115 static inline int
1116 between(uint32_t seq1, uint32_t seq2, uint32_t seq3)
1117 {
1118 	return seq3 - seq2 >= seq1 - seq2;
1119 }
1120 
1121 static inline uint32_t
1122 htcp_cong_time(struct htcp *ca)
1123 {
1124 	return sctp_get_tick_count() - ca->last_cong;
1125 }
1126 
1127 static inline uint32_t
1128 htcp_ccount(struct htcp *ca)
1129 {
1130 	return htcp_cong_time(ca) / ca->minRTT;
1131 }
1132 
1133 static inline void
1134 htcp_reset(struct htcp *ca)
1135 {
1136 	ca->undo_last_cong = ca->last_cong;
1137 	ca->undo_maxRTT = ca->maxRTT;
1138 	ca->undo_old_maxB = ca->old_maxB;
1139 	ca->last_cong = sctp_get_tick_count();
1140 }
1141 
1142 #ifdef SCTP_NOT_USED
1143 
1144 static uint32_t
1145 htcp_cwnd_undo(struct sctp_tcb *stcb, struct sctp_nets *net)
1146 {
1147 	net->htcp_ca.last_cong = net->htcp_ca.undo_last_cong;
1148 	net->htcp_ca.maxRTT = net->htcp_ca.undo_maxRTT;
1149 	net->htcp_ca.old_maxB = net->htcp_ca.undo_old_maxB;
1150 	return max(net->cwnd, ((net->ssthresh / net->mtu << 7) / net->htcp_ca.beta) * net->mtu);
1151 }
1152 
1153 #endif
1154 
1155 static inline void
1156 measure_rtt(struct sctp_tcb *stcb, struct sctp_nets *net)
1157 {
1158 	uint32_t srtt = net->lastsa >> 3;
1159 
1160 	/* keep track of minimum RTT seen so far, minRTT is zero at first */
1161 	if (net->htcp_ca.minRTT > srtt || !net->htcp_ca.minRTT)
1162 		net->htcp_ca.minRTT = srtt;
1163 
1164 	/* max RTT */
1165 	if (net->fast_retran_ip == 0 && net->ssthresh < 0xFFFF && htcp_ccount(&net->htcp_ca) > 3) {
1166 		if (net->htcp_ca.maxRTT < net->htcp_ca.minRTT)
1167 			net->htcp_ca.maxRTT = net->htcp_ca.minRTT;
1168 		if (net->htcp_ca.maxRTT < srtt && srtt <= net->htcp_ca.maxRTT + MSEC_TO_TICKS(20))
1169 			net->htcp_ca.maxRTT = srtt;
1170 	}
1171 }
1172 
1173 static void
1174 measure_achieved_throughput(struct sctp_tcb *stcb, struct sctp_nets *net)
1175 {
1176 	uint32_t now = sctp_get_tick_count();
1177 
1178 	if (net->fast_retran_ip == 0)
1179 		net->htcp_ca.bytes_acked = net->net_ack;
1180 
1181 	if (!use_bandwidth_switch)
1182 		return;
1183 
1184 	/* achieved throughput calculations */
1185 	/* JRS - not 100% sure of this statement */
1186 	if (net->fast_retran_ip == 1) {
1187 		net->htcp_ca.bytecount = 0;
1188 		net->htcp_ca.lasttime = now;
1189 		return;
1190 	}
1191 	net->htcp_ca.bytecount += net->net_ack;
1192 
1193 	if (net->htcp_ca.bytecount >= net->cwnd - ((net->htcp_ca.alpha >> 7 ? : 1) * net->mtu)
1194 	    && now - net->htcp_ca.lasttime >= net->htcp_ca.minRTT
1195 	    && net->htcp_ca.minRTT > 0) {
1196 		uint32_t cur_Bi = net->htcp_ca.bytecount / net->mtu * hz / (now - net->htcp_ca.lasttime);
1197 
1198 		if (htcp_ccount(&net->htcp_ca) <= 3) {
1199 			/* just after backoff */
1200 			net->htcp_ca.minB = net->htcp_ca.maxB = net->htcp_ca.Bi = cur_Bi;
1201 		} else {
1202 			net->htcp_ca.Bi = (3 * net->htcp_ca.Bi + cur_Bi) / 4;
1203 			if (net->htcp_ca.Bi > net->htcp_ca.maxB)
1204 				net->htcp_ca.maxB = net->htcp_ca.Bi;
1205 			if (net->htcp_ca.minB > net->htcp_ca.maxB)
1206 				net->htcp_ca.minB = net->htcp_ca.maxB;
1207 		}
1208 		net->htcp_ca.bytecount = 0;
1209 		net->htcp_ca.lasttime = now;
1210 	}
1211 }
1212 
1213 static inline void
1214 htcp_beta_update(struct htcp *ca, uint32_t minRTT, uint32_t maxRTT)
1215 {
1216 	if (use_bandwidth_switch) {
1217 		uint32_t maxB = ca->maxB;
1218 		uint32_t old_maxB = ca->old_maxB;
1219 
1220 		ca->old_maxB = ca->maxB;
1221 
1222 		if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
1223 			ca->beta = BETA_MIN;
1224 			ca->modeswitch = 0;
1225 			return;
1226 		}
1227 	}
1228 	if (ca->modeswitch && minRTT > (uint32_t) MSEC_TO_TICKS(10) && maxRTT) {
1229 		ca->beta = (minRTT << 7) / maxRTT;
1230 		if (ca->beta < BETA_MIN)
1231 			ca->beta = BETA_MIN;
1232 		else if (ca->beta > BETA_MAX)
1233 			ca->beta = BETA_MAX;
1234 	} else {
1235 		ca->beta = BETA_MIN;
1236 		ca->modeswitch = 1;
1237 	}
1238 }
1239 
1240 static inline void
1241 htcp_alpha_update(struct htcp *ca)
1242 {
1243 	uint32_t minRTT = ca->minRTT;
1244 	uint32_t factor = 1;
1245 	uint32_t diff = htcp_cong_time(ca);
1246 
1247 	if (diff > (uint32_t) hz) {
1248 		diff -= hz;
1249 		factor = 1 + (10 * diff + ((diff / 2) * (diff / 2) / hz)) / hz;
1250 	}
1251 	if (use_rtt_scaling && minRTT) {
1252 		uint32_t scale = (hz << 3) / (10 * minRTT);
1253 
1254 		scale = min(max(scale, 1U << 2), 10U << 3);	/* clamping ratio to
1255 								 * interval [0.5,10]<<3 */
1256 		factor = (factor << 3) / scale;
1257 		if (!factor)
1258 			factor = 1;
1259 	}
1260 	ca->alpha = 2 * factor * ((1 << 7) - ca->beta);
1261 	if (!ca->alpha)
1262 		ca->alpha = ALPHA_BASE;
1263 }
1264 
1265 /* After we have the rtt data to calculate beta, we'd still prefer to wait one
1266  * rtt before we adjust our beta to ensure we are working from a consistent
1267  * data.
1268  *
1269  * This function should be called when we hit a congestion event since only at
1270  * that point do we really have a real sense of maxRTT (the queues en route
1271  * were getting just too full now).
1272  */
1273 static void
1274 htcp_param_update(struct sctp_tcb *stcb, struct sctp_nets *net)
1275 {
1276 	uint32_t minRTT = net->htcp_ca.minRTT;
1277 	uint32_t maxRTT = net->htcp_ca.maxRTT;
1278 
1279 	htcp_beta_update(&net->htcp_ca, minRTT, maxRTT);
1280 	htcp_alpha_update(&net->htcp_ca);
1281 
1282 	/*
1283 	 * add slowly fading memory for maxRTT to accommodate routing
1284 	 * changes etc
1285 	 */
1286 	if (minRTT > 0 && maxRTT > minRTT)
1287 		net->htcp_ca.maxRTT = minRTT + ((maxRTT - minRTT) * 95) / 100;
1288 }
1289 
1290 static uint32_t
1291 htcp_recalc_ssthresh(struct sctp_tcb *stcb, struct sctp_nets *net)
1292 {
1293 	htcp_param_update(stcb, net);
1294 	return max(((net->cwnd / net->mtu * net->htcp_ca.beta) >> 7) * net->mtu, 2U * net->mtu);
1295 }
1296 
1297 static void
1298 htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
1299 {
1300 	/*-
1301 	 * How to handle these functions?
1302          *	if (!tcp_is_cwnd_limited(sk, in_flight)) RRS - good question.
1303 	 *		return;
1304 	 */
1305 	if (net->cwnd <= net->ssthresh) {
1306 		/* We are in slow start */
1307 		if (net->flight_size + net->net_ack >= net->cwnd) {
1308 			if (net->net_ack > (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable))) {
1309 				net->cwnd += (net->mtu * SCTP_BASE_SYSCTL(sctp_L2_abc_variable));
1310 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1311 					sctp_log_cwnd(stcb, net, net->mtu,
1312 					    SCTP_CWND_LOG_FROM_SS);
1313 				}
1314 			} else {
1315 				net->cwnd += net->net_ack;
1316 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1317 					sctp_log_cwnd(stcb, net, net->net_ack,
1318 					    SCTP_CWND_LOG_FROM_SS);
1319 				}
1320 			}
1321 		} else {
1322 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1323 				sctp_log_cwnd(stcb, net, net->net_ack,
1324 				    SCTP_CWND_LOG_NOADV_SS);
1325 			}
1326 		}
1327 	} else {
1328 		measure_rtt(stcb, net);
1329 
1330 		/*
1331 		 * In dangerous area, increase slowly. In theory this is
1332 		 * net->cwnd += alpha / net->cwnd
1333 		 */
1334 		/* What is snd_cwnd_cnt?? */
1335 		if (((net->partial_bytes_acked / net->mtu * net->htcp_ca.alpha) >> 7) * net->mtu >= net->cwnd) {
1336 			/*-
1337 			 * Does SCTP have a cwnd clamp?
1338 			 * if (net->snd_cwnd < net->snd_cwnd_clamp) - Nope (RRS).
1339 			 */
1340 			net->cwnd += net->mtu;
1341 			net->partial_bytes_acked = 0;
1342 			htcp_alpha_update(&net->htcp_ca);
1343 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1344 				sctp_log_cwnd(stcb, net, net->mtu,
1345 				    SCTP_CWND_LOG_FROM_CA);
1346 			}
1347 		} else {
1348 			net->partial_bytes_acked += net->net_ack;
1349 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1350 				sctp_log_cwnd(stcb, net, net->net_ack,
1351 				    SCTP_CWND_LOG_NOADV_CA);
1352 			}
1353 		}
1354 
1355 		net->htcp_ca.bytes_acked = net->mtu;
1356 	}
1357 }
1358 
1359 #ifdef SCTP_NOT_USED
1360 /* Lower bound on congestion window. */
1361 static uint32_t
1362 htcp_min_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net)
1363 {
1364 	return net->ssthresh;
1365 }
1366 
1367 #endif
1368 
1369 static void
1370 htcp_init(struct sctp_tcb *stcb, struct sctp_nets *net)
1371 {
1372 	memset(&net->htcp_ca, 0, sizeof(struct htcp));
1373 	net->htcp_ca.alpha = ALPHA_BASE;
1374 	net->htcp_ca.beta = BETA_MIN;
1375 	net->htcp_ca.bytes_acked = net->mtu;
1376 	net->htcp_ca.last_cong = sctp_get_tick_count();
1377 }
1378 
1379 static void
1380 sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
1381 {
1382 	/*
1383 	 * We take the max of the burst limit times a MTU or the
1384 	 * INITIAL_CWND. We then limit this to 4 MTU's of sending.
1385 	 */
1386 	net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
1387 	net->ssthresh = stcb->asoc.peers_rwnd;
1388 	htcp_init(stcb, net);
1389 
1390 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
1391 		sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION);
1392 	}
1393 }
1394 
1395 static void
1396 sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
1397     struct sctp_association *asoc,
1398     int accum_moved, int reneged_all, int will_exit)
1399 {
1400 	struct sctp_nets *net;
1401 
1402 	/******************************/
1403 	/* update cwnd and Early FR   */
1404 	/******************************/
1405 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1406 
1407 #ifdef JANA_CMT_FAST_RECOVERY
1408 		/*
1409 		 * CMT fast recovery code. Need to debug.
1410 		 */
1411 		if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
1412 			if (SCTP_TSN_GE(asoc->last_acked_seq, net->fast_recovery_tsn) ||
1413 			    SCTP_TSN_GE(net->pseudo_cumack, net->fast_recovery_tsn)) {
1414 				net->will_exit_fast_recovery = 1;
1415 			}
1416 		}
1417 #endif
1418 		if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
1419 			/*
1420 			 * So, first of all do we need to have a Early FR
1421 			 * timer running?
1422 			 */
1423 			if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
1424 			    (net->ref_count > 1) &&
1425 			    (net->flight_size < net->cwnd)) ||
1426 			    (reneged_all)) {
1427 				/*
1428 				 * yes, so in this case stop it if its
1429 				 * running, and then restart it. Reneging
1430 				 * all is a special case where we want to
1431 				 * run the Early FR timer and then force the
1432 				 * last few unacked to be sent, causing us
1433 				 * to illicit a sack with gaps to force out
1434 				 * the others.
1435 				 */
1436 				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
1437 					SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
1438 					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
1439 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
1440 				}
1441 				SCTP_STAT_INCR(sctps_earlyfrstrid);
1442 				sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
1443 			} else {
1444 				/* No, stop it if its running */
1445 				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
1446 					SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
1447 					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
1448 					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
1449 				}
1450 			}
1451 		}
1452 		/* if nothing was acked on this destination skip it */
1453 		if (net->net_ack == 0) {
1454 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1455 				sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
1456 			}
1457 			continue;
1458 		}
1459 		if (net->net_ack2 > 0) {
1460 			/*
1461 			 * Karn's rule applies to clearing error count, this
1462 			 * is optional.
1463 			 */
1464 			net->error_count = 0;
1465 			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
1466 			    SCTP_ADDR_NOT_REACHABLE) {
1467 				/* addr came good */
1468 				net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
1469 				net->dest_state |= SCTP_ADDR_REACHABLE;
1470 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
1471 				    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
1472 				/* now was it the primary? if so restore */
1473 				if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
1474 					(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
1475 				}
1476 			}
1477 			/*
1478 			 * JRS 5/14/07 - If CMT PF is on and the destination
1479 			 * is in PF state, set the destination to active
1480 			 * state and set the cwnd to one or two MTU's based
1481 			 * on whether PF1 or PF2 is being used.
1482 			 *
1483 			 * Should we stop any running T3 timer here?
1484 			 */
1485 			if ((asoc->sctp_cmt_on_off > 0) &&
1486 			    (asoc->sctp_cmt_pf > 0) &&
1487 			    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
1488 				net->dest_state &= ~SCTP_ADDR_PF;
1489 				net->cwnd = net->mtu * asoc->sctp_cmt_pf;
1490 				SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
1491 				    net, net->cwnd);
1492 				/*
1493 				 * Since the cwnd value is explicitly set,
1494 				 * skip the code that updates the cwnd
1495 				 * value.
1496 				 */
1497 				goto skip_cwnd_update;
1498 			}
1499 		}
1500 #ifdef JANA_CMT_FAST_RECOVERY
1501 		/*
1502 		 * CMT fast recovery code
1503 		 */
1504 		/*
1505 		 * if (sctp_cmt_on_off > 0 && net->fast_retran_loss_recovery
1506 		 * && net->will_exit_fast_recovery == 0) { @@@ Do something
1507 		 * } else if (sctp_cmt_on_off == 0 &&
1508 		 * asoc->fast_retran_loss_recovery && will_exit == 0) {
1509 		 */
1510 #endif
1511 
1512 		if (asoc->fast_retran_loss_recovery &&
1513 		    will_exit == 0 &&
1514 		    (asoc->sctp_cmt_on_off == 0)) {
1515 			/*
1516 			 * If we are in loss recovery we skip any cwnd
1517 			 * update
1518 			 */
1519 			goto skip_cwnd_update;
1520 		}
1521 		/*
1522 		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
1523 		 * moved.
1524 		 */
1525 		if (accum_moved ||
1526 		    ((asoc->sctp_cmt_on_off > 0) && net->new_pseudo_cumack)) {
1527 			htcp_cong_avoid(stcb, net);
1528 			measure_achieved_throughput(stcb, net);
1529 		} else {
1530 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
1531 				sctp_log_cwnd(stcb, net, net->mtu,
1532 				    SCTP_CWND_LOG_NO_CUMACK);
1533 			}
1534 		}
1535 skip_cwnd_update:
1536 		/*
1537 		 * NOW, according to Karn's rule do we need to restore the
1538 		 * RTO timer back? Check our net_ack2. If not set then we
1539 		 * have a ambiguity.. i.e. all data ack'd was sent to more
1540 		 * than one place.
1541 		 */
1542 		if (net->net_ack2) {
1543 			/* restore any doubled timers */
1544 			net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1;
1545 			if (net->RTO < stcb->asoc.minrto) {
1546 				net->RTO = stcb->asoc.minrto;
1547 			}
1548 			if (net->RTO > stcb->asoc.maxrto) {
1549 				net->RTO = stcb->asoc.maxrto;
1550 			}
1551 		}
1552 	}
1553 }
1554 
1555 static void
1556 sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
1557     struct sctp_association *asoc)
1558 {
1559 	struct sctp_nets *net;
1560 
1561 	/*
1562 	 * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off > 0) &&
1563 	 * (net->fast_retran_loss_recovery == 0)))
1564 	 */
1565 	TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
1566 		if ((asoc->fast_retran_loss_recovery == 0) ||
1567 		    (asoc->sctp_cmt_on_off > 0)) {
1568 			/* out of a RFC2582 Fast recovery window? */
1569 			if (net->net_ack > 0) {
1570 				/*
1571 				 * per section 7.2.3, are there any
1572 				 * destinations that had a fast retransmit
1573 				 * to them. If so what we need to do is
1574 				 * adjust ssthresh and cwnd.
1575 				 */
1576 				struct sctp_tmit_chunk *lchk;
1577 				int old_cwnd = net->cwnd;
1578 
1579 				/* JRS - reset as if state were changed */
1580 				htcp_reset(&net->htcp_ca);
1581 				net->ssthresh = htcp_recalc_ssthresh(stcb, net);
1582 				net->cwnd = net->ssthresh;
1583 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1584 					sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
1585 					    SCTP_CWND_LOG_FROM_FR);
1586 				}
1587 				lchk = TAILQ_FIRST(&asoc->send_queue);
1588 
1589 				net->partial_bytes_acked = 0;
1590 				/* Turn on fast recovery window */
1591 				asoc->fast_retran_loss_recovery = 1;
1592 				if (lchk == NULL) {
1593 					/* Mark end of the window */
1594 					asoc->fast_recovery_tsn = asoc->sending_seq - 1;
1595 				} else {
1596 					asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
1597 				}
1598 
1599 				/*
1600 				 * CMT fast recovery -- per destination
1601 				 * recovery variable.
1602 				 */
1603 				net->fast_retran_loss_recovery = 1;
1604 
1605 				if (lchk == NULL) {
1606 					/* Mark end of the window */
1607 					net->fast_recovery_tsn = asoc->sending_seq - 1;
1608 				} else {
1609 					net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
1610 				}
1611 
1612 				/*
1613 				 * Disable Nonce Sum Checking and store the
1614 				 * resync tsn
1615 				 */
1616 				asoc->nonce_sum_check = 0;
1617 				asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1;
1618 
1619 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
1620 				    stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
1621 				sctp_timer_start(SCTP_TIMER_TYPE_SEND,
1622 				    stcb->sctp_ep, stcb, net);
1623 			}
1624 		} else if (net->net_ack > 0) {
1625 			/*
1626 			 * Mark a peg that we WOULD have done a cwnd
1627 			 * reduction but RFC2582 prevented this action.
1628 			 */
1629 			SCTP_STAT_INCR(sctps_fastretransinrtt);
1630 		}
1631 	}
1632 }
1633 
1634 static void
1635 sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
1636     struct sctp_nets *net)
1637 {
1638 	int old_cwnd = net->cwnd;
1639 
1640 	/* JRS - reset as if the state were being changed to timeout */
1641 	htcp_reset(&net->htcp_ca);
1642 	net->ssthresh = htcp_recalc_ssthresh(stcb, net);
1643 	net->cwnd = net->mtu;
1644 	net->partial_bytes_acked = 0;
1645 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1646 		sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
1647 	}
1648 }
1649 
1650 static void
1651 sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
1652     struct sctp_tcb *stcb, struct sctp_nets *net)
1653 {
1654 	int old_cwnd;
1655 
1656 	old_cwnd = net->cwnd;
1657 
1658 	sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
1659 	net->htcp_ca.last_cong = sctp_get_tick_count();
1660 	/*
1661 	 * make a small adjustment to cwnd and force to CA.
1662 	 */
1663 	if (net->cwnd > net->mtu)
1664 		/* drop down one MTU after sending */
1665 		net->cwnd -= net->mtu;
1666 	if (net->cwnd < net->ssthresh)
1667 		/* still in SS move to CA */
1668 		net->ssthresh = net->cwnd - 1;
1669 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1670 		sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
1671 	}
1672 }
1673 
1674 static void
1675 sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
1676     struct sctp_nets *net)
1677 {
1678 	int old_cwnd;
1679 
1680 	old_cwnd = net->cwnd;
1681 
1682 	/* JRS - reset hctp as if state changed */
1683 	htcp_reset(&net->htcp_ca);
1684 	SCTP_STAT_INCR(sctps_ecnereducedcwnd);
1685 	net->ssthresh = htcp_recalc_ssthresh(stcb, net);
1686 	if (net->ssthresh < net->mtu) {
1687 		net->ssthresh = net->mtu;
1688 		/* here back off the timer as well, to slow us down */
1689 		net->RTO <<= 1;
1690 	}
1691 	net->cwnd = net->ssthresh;
1692 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1693 		sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
1694 	}
1695 }
1696 
1697 struct sctp_cc_functions sctp_cc_functions[] = {
1698 	{
1699 		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
1700 		.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
1701 		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
1702 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
1703 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
1704 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
1705 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
1706 		.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
1707 	},
1708 	{
1709 		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
1710 		.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
1711 		.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
1712 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
1713 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
1714 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
1715 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
1716 		.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
1717 	},
1718 	{
1719 		.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
1720 		.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
1721 		.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
1722 		.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
1723 		.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
1724 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
1725 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
1726 		.sctp_cwnd_update_after_fr_timer = sctp_htcp_cwnd_update_after_fr_timer
1727 	}
1728 };
1729