+always_inline u8
+sctp_next_avail_subconn (sctp_connection_t * sctp_conn)
+{
+ u8 i;
+
+ for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
+ {
+ if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
+ return i;
+ }
+ return MAX_SCTP_CONNECTIONS;
+}
+
+always_inline void
+update_smallest_pmtu_idx (sctp_connection_t * sctp_conn)
+{
+ u8 i;
+ u8 smallest_pmtu_index = SCTP_PRIMARY_PATH_IDX;
+
+ for (i = 1; i < MAX_SCTP_CONNECTIONS; i++)
+ {
+ if (sctp_conn->sub_conn[i].state != SCTP_SUBCONN_STATE_DOWN)
+ {
+ if (sctp_conn->sub_conn[i].PMTU <
+ sctp_conn->sub_conn[smallest_pmtu_index].PMTU)
+ smallest_pmtu_index = i;
+ }
+ }
+
+ sctp_conn->smallest_PMTU_idx = smallest_pmtu_index;
+}
+
+/* As per RFC4960; section 7.2.1: Slow-Start */
+always_inline void
+sctp_init_cwnd (sctp_connection_t * sctp_conn)
+{
+ u8 i;
+ for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
+ {
+ /* Section 7.2.1; point (1) */
+ sctp_conn->sub_conn[i].cwnd =
+ clib_min (4 * sctp_conn->sub_conn[i].PMTU,
+ clib_max (2 * sctp_conn->sub_conn[i].PMTU, 4380));
+
+ /* Section 7.2.1; point (3) */
+ sctp_conn->sub_conn[i].ssthresh = SCTP_INITIAL_SSHTRESH;
+
+ /* Section 7.2.2; point (1) */
+ sctp_conn->sub_conn[i].partially_acked_bytes = 0;
+ }
+}
+
+always_inline u8
+sctp_in_cong_recovery (sctp_connection_t * sctp_conn, u8 idx)
+{
+ return 0;
+}
+
+always_inline u8
+cwnd_fully_utilized (sctp_connection_t * sctp_conn, u8 idx)
+{
+ if (sctp_conn->sub_conn[idx].cwnd == 0)
+ return 1;
+ return 0;
+}
+
+/* As per RFC4960; section 7.2.1: Slow-Start */
+always_inline void
+update_cwnd (sctp_connection_t * sctp_conn)
+{
+ u8 i;
+ u32 inflight = sctp_conn->next_tsn - sctp_conn->last_unacked_tsn;
+
+ for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
+ {
+ /* Section 7.2.1; point (2) */
+ if (sctp_conn->sub_conn[i].is_retransmitting)
+ {
+ sctp_conn->sub_conn[i].cwnd = 1 * sctp_conn->sub_conn[i].PMTU;
+ continue;
+ }
+
+ /* Section 7.2.2; point (4) */
+ if (sctp_conn->sub_conn[i].last_data_ts >
+ sctp_time_now () + SCTP_DATA_IDLE_INTERVAL)
+ {
+ sctp_conn->sub_conn[i].cwnd =
+ clib_max (sctp_conn->sub_conn[i].cwnd / 2,
+ 4 * sctp_conn->sub_conn[i].PMTU);
+ continue;
+ }
+
+ /* Section 7.2.1; point (5) */
+ if (sctp_conn->sub_conn[i].cwnd <= sctp_conn->sub_conn[i].ssthresh)
+ {
+ if (!cwnd_fully_utilized (sctp_conn, i))
+ continue;
+
+ if (sctp_in_cong_recovery (sctp_conn, i))
+ continue;
+
+ sctp_conn->sub_conn[i].cwnd =
+ clib_min (sctp_conn->sub_conn[i].PMTU, 1);
+ }
+
+ /* Section 6.1; point (D) */
+ if ((inflight + SCTP_RTO_BURST * sctp_conn->sub_conn[i].PMTU) <
+ sctp_conn->sub_conn[i].cwnd)
+ sctp_conn->sub_conn[i].cwnd =
+ inflight + SCTP_RTO_BURST * sctp_conn->sub_conn[i].PMTU;
+ }
+}
+