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