+ if (si->si_ack == cb->s_smax + 1) {
+ cb->s_timer[SPPT_REXMT] = 0;
+ cb->s_flags |= SF_RXT;
+ } else if (cb->s_timer[SPPT_PERSIST] == 0)
+ cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
+ /*
+ * When new data is acked, open the congestion window.
+ * If the window gives us less than ssthresh packets
+ * in flight, open exponentially (maxseg at a time).
+ * Otherwise open linearly (maxseg^2 / cwnd at a time).
+ */
+ incr = CUNIT;
+ if (cb->s_cwnd > cb->s_ssthresh)
+ incr = max(incr * incr / cb->s_cwnd, 1);
+ cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
+ /*
+ * Trim Acked data from output queue.
+ */
+ while ((m = so->so_snd.sb_mb) != NULL) {
+ if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack))
+ sbdroprecord(&so->so_snd);
+ else
+ break;
+ }
+ sowwakeup(so);
+ cb->s_rack = si->si_ack;
+update_window:
+ if (SSEQ_LT(cb->s_snxt, cb->s_rack))
+ cb->s_snxt = cb->s_rack;
+ if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq &&
+ (SSEQ_LT(cb->s_swl2, si->si_ack) ||
+ cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) {
+ /* keep track of pure window updates */
+ if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack
+ && SSEQ_LT(cb->s_ralo, si->si_alo)) {
+ sppstat.spps_rcvwinupd++;
+ sppstat.spps_rcvdupack--;
+ }
+ cb->s_ralo = si->si_alo;
+ cb->s_swl1 = si->si_seq;
+ cb->s_swl2 = si->si_ack;
+ cb->s_swnd = (1 + si->si_alo - si->si_ack);
+ if (cb->s_swnd > cb->s_smxw)
+ cb->s_smxw = cb->s_swnd;
+ cb->s_flags |= SF_WIN;