+#define ABS(x) ((x) > 0) ? (x) : -(x);
+
+always_inline void
+sctp_calculate_rto (sctp_connection_t * sctp_conn, u8 conn_idx)
+{
+ /* See RFC4960, 6.3.1. RTO Calculation */
+ u32 RTO = 0;
+ f32 RTTVAR = 0;
+ u32 now = sctp_time_now ();
+ u32 prev_ts = sctp_conn->sub_conn[conn_idx].rtt_ts;
+ u32 R = prev_ts - now;
+
+ if (sctp_conn->sub_conn[conn_idx].RTO == 0) // C1: Let's initialize our RTO
+ {
+ sctp_conn->sub_conn[conn_idx].RTO = SCTP_RTO_MIN;
+ return;
+ }
+
+ if (sctp_conn->sub_conn[conn_idx].RTO == SCTP_RTO_MIN && sctp_conn->sub_conn[conn_idx].SRTT == 0) // C2: First RTT calculation
+ {
+ sctp_conn->sub_conn[conn_idx].SRTT = R;
+ RTTVAR = R / 2;
+
+ if (RTTVAR == 0)
+ RTTVAR = 100e-3; /* 100 ms */
+
+ sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
+ }
+ else // C3: RTT already exists; let's recalculate
+ {
+ RTTVAR = (1 - SCTP_RTO_BETA) * sctp_conn->sub_conn[conn_idx].RTTVAR +
+ SCTP_RTO_BETA * ABS (sctp_conn->sub_conn[conn_idx].SRTT - R);
+
+ if (RTTVAR == 0)
+ RTTVAR = 100e-3; /* 100 ms */
+
+ sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
+
+ sctp_conn->sub_conn[conn_idx].SRTT =
+ (1 - SCTP_RTO_ALPHA) * sctp_conn->sub_conn[conn_idx].SRTT +
+ SCTP_RTO_ALPHA * R;
+ }
+
+ RTO =
+ sctp_conn->sub_conn[conn_idx].SRTT +
+ 4 * sctp_conn->sub_conn[conn_idx].RTTVAR;
+ if (RTO < SCTP_RTO_MIN) // C6
+ RTO = SCTP_RTO_MIN;
+
+ if (RTO > SCTP_RTO_MAX) // C7
+ RTO = SCTP_RTO_MAX;
+
+ sctp_conn->sub_conn[conn_idx].RTO = RTO;
+}
+