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