+/*
+ * When a new ack with SACK is received, check if it indicates packet
+ * reordering. If there is packet reordering, the socket is marked and
+ * the late time offset by which the packet was reordered with
+ * respect to its closest neighboring packets is computed.
+ */
+static void
+tcp_sack_detect_reordering(struct tcpcb *tp, struct sackhole *s,
+ tcp_seq sacked_seq, tcp_seq snd_fack)
+{
+ int32_t rext = 0, reordered = 0;
+
+ /*
+ * If the SACK hole is past snd_fack, this is from new SACK
+ * information, so we can ignore it.
+ */
+ if (SEQ_GT(s->end, snd_fack))
+ return;
+ /*
+ * If there has been a retransmit timeout, then the timestamp on
+ * the SACK segment will be newer. This might lead to a
+ * false-positive. Avoid re-ordering detection in this case.
+ */
+ if (tp->t_rxtshift > 0)
+ return;
+
+ /*
+ * Detect reordering from SACK information by checking
+ * if recently sacked data was never retransmitted from this hole.
+ */
+ if (SEQ_LT(s->rxmit, sacked_seq)) {
+ reordered = 1;
+ tcpstat.tcps_avoid_rxmt++;
+ }
+
+ if (reordered) {
+ if (!(tp->t_flagsext & TF_PKTS_REORDERED)) {
+ tp->t_flagsext |= TF_PKTS_REORDERED;
+ tcpstat.tcps_detect_reordering++;
+ }
+
+ tcpstat.tcps_reordered_pkts++;
+
+ VERIFY(SEQ_GEQ(snd_fack, s->rxmit));
+
+ if (s->rxmit_start > 0) {
+ rext = timer_diff(tcp_now, 0, s->rxmit_start, 0);
+ if (rext < 0)
+ return;
+
+ /*
+ * We take the maximum reorder window to schedule
+ * DELAYFR timer as that will take care of jitter
+ * on the network path.
+ *
+ * Computing average and standard deviation seems
+ * to cause unnecessary retransmissions when there
+ * is high jitter.
+ *
+ * We set a maximum of SRTT/2 and a minimum of
+ * 10 ms on the reorder window.
+ */
+ tp->t_reorderwin = max(tp->t_reorderwin, rext);
+ tp->t_reorderwin = min(tp->t_reorderwin,
+ (tp->t_srtt >> (TCP_RTT_SHIFT - 1)));
+ tp->t_reorderwin = max(tp->t_reorderwin, 10);
+ }
+ }
+}