root/sys/netinet/tcp_stacks/rack.c
/*-
 * Copyright (c) 2016-2020 Netflix, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <sys/cdefs.h>
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_ratelimit.h"
#include "opt_kern_tls.h"
#if defined(INET) || defined(INET6)
#include <sys/param.h>
#include <sys/arb.h>
#include <sys/module.h>
#include <sys/kernel.h>
#ifdef TCP_HHOOK
#include <sys/hhook.h>
#endif
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/proc.h>           /* for proc0 declaration */
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#ifdef STATS
#include <sys/qmath.h>
#include <sys/tree.h>
#include <sys/stats.h> /* Must come after qmath.h and tree.h */
#else
#include <sys/tree.h>
#endif
#include <sys/refcount.h>
#include <sys/queue.h>
#include <sys/tim_filter.h>
#include <sys/smp.h>
#include <sys/kthread.h>
#include <sys/kern_prefetch.h>
#include <sys/protosw.h>
#ifdef TCP_ACCOUNTING
#include <sys/sched.h>
#include <machine/cpu.h>
#endif
#include <vm/uma.h>

#include <net/route.h>
#include <net/route/nhop.h>
#include <net/vnet.h>

#define TCPSTATES               /* for logging */

#include <netinet/in.h>
#include <netinet/in_kdtrace.h>
#include <netinet/in_pcb.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip6.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6_var.h>
#include <netinet/tcp.h>
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcp_log_buf.h>
#include <netinet/tcp_syncache.h>
#include <netinet/tcp_hpts.h>
#include <netinet/tcp_ratelimit.h>
#include <netinet/tcp_accounting.h>
#include <netinet/tcpip.h>
#include <netinet/cc/cc.h>
#include <netinet/cc/cc_newreno.h>
#include <netinet/tcp_fastopen.h>
#include <netinet/tcp_lro.h>
#ifdef NETFLIX_SHARED_CWND
#include <netinet/tcp_shared_cwnd.h>
#endif
#ifdef TCP_OFFLOAD
#include <netinet/tcp_offload.h>
#endif
#ifdef INET6
#include <netinet6/tcp6_var.h>
#endif
#include <netinet/tcp_ecn.h>

#include <netipsec/ipsec_support.h>

#if defined(IPSEC) || defined(IPSEC_SUPPORT)
#include <netipsec/ipsec.h>
#include <netipsec/ipsec6.h>
#endif                          /* IPSEC */

#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <machine/in_cksum.h>

#ifdef MAC
#include <security/mac/mac_framework.h>
#endif
#include "sack_filter.h"
#include "tcp_rack.h"
#include "tailq_hash.h"
#include "rack_bbr_common.h"

uma_zone_t rack_zone;
uma_zone_t rack_pcb_zone;

#ifndef TICKS2SBT
#define TICKS2SBT(__t)  (tick_sbt * ((sbintime_t)(__t)))
#endif

VNET_DECLARE(uint32_t, newreno_beta);
VNET_DECLARE(uint32_t, newreno_beta_ecn);
#define V_newreno_beta VNET(newreno_beta)
#define V_newreno_beta_ecn VNET(newreno_beta_ecn)

#define M_TCPFSB        __CONCAT(M_TCPFSB, STACKNAME)
#define M_TCPDO         __CONCAT(M_TCPDO, STACKNAME)

MALLOC_DEFINE(M_TCPFSB, "tcp_fsb_" __XSTRING(STACKNAME), "TCP fast send block");
MALLOC_DEFINE(M_TCPDO, "tcp_do_" __XSTRING(STACKNAME), "TCP deferred options");
MALLOC_DEFINE(M_TCPPCM, "tcp_pcm_" __XSTRING(STACKNAME), "TCP PCM measurement information");

struct sysctl_ctx_list rack_sysctl_ctx;
struct sysctl_oid *rack_sysctl_root;

#define CUM_ACKED 1
#define SACKED 2

/*
 * The RACK module incorporates a number of
 * TCP ideas that have been put out into the IETF
 * over the last few years:
 * - Matt Mathis's Rate Halving which slowly drops
 *    the congestion window so that the ack clock can
 *    be maintained during a recovery.
 * - Yuchung Cheng's RACK TCP (for which its named) that
 *    will stop us using the number of dup acks and instead
 *    use time as the gage of when we retransmit.
 * - Reorder Detection of RFC4737 and the Tail-Loss probe draft
 *    of Dukkipati et.al.
 * RACK depends on SACK, so if an endpoint arrives that
 * cannot do SACK the state machine below will shuttle the
 * connection back to using the "default" TCP stack that is
 * in FreeBSD.
 *
 * To implement RACK the original TCP stack was first decomposed
 * into a functional state machine with individual states
 * for each of the possible TCP connection states. The do_segment
 * functions role in life is to mandate the connection supports SACK
 * initially and then assure that the RACK state matches the conenction
 * state before calling the states do_segment function. Each
 * state is simplified due to the fact that the original do_segment
 * has been decomposed and we *know* what state we are in (no
 * switches on the state) and all tests for SACK are gone. This
 * greatly simplifies what each state does.
 *
 * TCP output is also over-written with a new version since it
 * must maintain the new rack scoreboard.
 *
 */
static int32_t rack_tlp_thresh = 1;
static int32_t rack_tlp_limit = 2;      /* No more than 2 TLPs w-out new data */
static int32_t rack_tlp_use_greater = 1;
static int32_t rack_reorder_thresh = 2;
static int32_t rack_reorder_fade = 60000000;    /* 0 - never fade, def 60,000,000
                                                 * - 60 seconds */
static uint32_t rack_pcm_every_n_rounds = 100;
static uint32_t rack_pcm_blast = 0;
static uint32_t rack_pcm_is_enabled = 1;
static uint8_t rack_ssthresh_rest_rto_rec = 0; /* Do we restore ssthresh when we have rec -> rto -> rec */

static uint32_t rack_gp_gain_req = 1200;                /* Amount percent wise required to gain to record a round as "gaining" */
static uint32_t rack_rnd_cnt_req = 0x10005;             /* Default number of rounds if we are below rack_gp_gain_req where we exit ss */


static int32_t rack_rxt_scoreboard_clear_thresh = 2;
static int32_t rack_dnd_default = 0;            /* For rr_conf = 3, what is the default for dnd */
static int32_t rack_rxt_controls = 0;
static int32_t rack_fill_cw_state = 0;
static uint8_t rack_req_measurements = 1;
static uint32_t rack_rtt_divisor = 2;
static int32_t rack_enable_hw_pacing = 0; /* Due to CCSP keep it off by default */
static int32_t rack_hw_rate_caps = 0; /* 1; */
static int32_t rack_hw_rate_cap_per = 0;        /* 0 -- off  */
static int32_t rack_hw_rate_min = 0; /* 1500000;*/
static int32_t rack_hw_rate_to_low = 0; /* 1200000; */
static int32_t rack_hw_up_only = 0;
static int32_t rack_stats_gets_ms_rtt = 1;
static int32_t rack_prr_addbackmax = 2;
static int32_t rack_do_hystart = 0;
static int32_t rack_apply_rtt_with_reduced_conf = 0;
static int32_t rack_hibeta_setting = 0;
static int32_t rack_default_pacing_divisor = 250;
static uint16_t rack_pacing_min_seg = 0;
static int32_t rack_timely_off = 0;

static int32_t rack_pkt_delay = 1000;
static int32_t rack_send_a_lot_in_prr = 1;
static int32_t rack_min_to = 1000;      /* Number of microsecond  min timeout */
static int32_t rack_verbose_logging = 0;
static int32_t rack_ignore_data_after_close = 1;
static int32_t rack_enable_shared_cwnd = 1;
static int32_t rack_use_cmp_acks = 1;
static int32_t rack_use_fsb = 1;
static int32_t rack_use_rfo = 1;
static int32_t rack_use_rsm_rfo = 1;
static int32_t rack_max_abc_post_recovery = 2;
static int32_t rack_client_low_buf = 0;
static int32_t rack_dsack_std_based = 0x3;      /* bit field bit 1 sets rc_rack_tmr_std_based and bit 2 sets rc_rack_use_dsack */
static int32_t rack_bw_multipler = 0;           /* Limit on fill cw's jump up to be this x gp_est */
#ifdef TCP_ACCOUNTING
static int32_t rack_tcp_accounting = 0;
#endif
static int32_t rack_limits_scwnd = 1;
static int32_t rack_enable_mqueue_for_nonpaced = 0;
static int32_t rack_hybrid_allow_set_maxseg = 0;
static int32_t rack_disable_prr = 0;
static int32_t use_rack_rr = 1;
static int32_t rack_non_rxt_use_cr = 0; /* does a non-rxt in recovery use the configured rate (ss/ca)? */
static int32_t rack_persist_min = 250000;       /* 250usec */
static int32_t rack_persist_max = 2000000;      /* 2 Second in usec's */
static int32_t rack_honors_hpts_min_to =  1;    /* Do we honor the hpts minimum time out for pacing timers */
static uint32_t rack_max_reduce = 10;           /* Percent we can reduce pacing delay by */
static int32_t rack_sack_not_required = 1;      /* set to one to allow non-sack to use rack */
static int32_t rack_limit_time_with_srtt = 0;
static int32_t rack_autosndbuf_inc = 20;        /* In percentage form */
static int32_t rack_enobuf_hw_boost_mult = 0;   /* How many times the hw rate we boost pacing delay using time_between */
static int32_t rack_enobuf_hw_max = 12000;      /* 12 ms in usecs */
static int32_t rack_enobuf_hw_min = 10000;      /* 10 ms in usecs */
static int32_t rack_hw_rwnd_factor = 2;         /* How many max_segs the rwnd must be before we hold off sending */
static int32_t rack_hw_check_queue = 0;         /* Do we always pre-check queue depth of a hw queue */

/*
 * Currently regular tcp has a rto_min of 30ms
 * the backoff goes 12 times so that ends up
 * being a total of 122.850 seconds before a
 * connection is killed.
 */
static uint32_t rack_def_data_window = 20;
static uint32_t rack_goal_bdp = 2;
static uint32_t rack_min_srtts = 1;
static uint32_t rack_min_measure_usec = 0;
static int32_t rack_tlp_min = 10000;    /* 10ms */
static int32_t rack_rto_min = 30000;    /* 30,000 usec same as main freebsd */
static int32_t rack_rto_max = 4000000;  /* 4 seconds in usec's */
static const int32_t rack_free_cache = 2;
static int32_t rack_hptsi_segments = 40;
static int32_t rack_rate_sample_method = USE_RTT_LOW;
static int32_t rack_pace_every_seg = 0;
static int32_t rack_delayed_ack_time = 40000;   /* 40ms in usecs */
static int32_t rack_pacing_delay_reduction = 4;
static int32_t rack_wma_divisor = 8;            /* For WMA calculation */
static int32_t rack_cwnd_block_ends_measure = 0;
static int32_t rack_rwnd_block_ends_measure = 0;
static int32_t rack_def_profile = 0;

static int32_t rack_lower_cwnd_at_tlp = 0;
static int32_t rack_always_send_oldest = 0;
static int32_t rack_tlp_threshold_use = TLP_USE_TWO_ONE;

static uint16_t rack_per_of_gp_ss = 250;        /* 250 % slow-start */
static uint16_t rack_per_of_gp_ca = 200;        /* 200 % congestion-avoidance */
static uint16_t rack_per_of_gp_rec = 200;       /* 200 % of bw */

/* Probertt */
static uint16_t rack_per_of_gp_probertt = 60;   /* 60% of bw */
static uint16_t rack_per_of_gp_lowthresh = 40;  /* 40% is bottom */
static uint16_t rack_per_of_gp_probertt_reduce = 10; /* 10% reduction */
static uint16_t rack_atexit_prtt_hbp = 130;     /* Clamp to 130% on exit prtt if highly buffered path */
static uint16_t rack_atexit_prtt = 130; /* Clamp to 100% on exit prtt if non highly buffered path */

static uint32_t rack_max_drain_wait = 2;        /* How man gp srtt's before we give up draining */
static uint32_t rack_must_drain = 1;            /* How many GP srtt's we *must* wait */
static uint32_t rack_probertt_use_min_rtt_entry = 1;    /* Use the min to calculate the goal else gp_srtt */
static uint32_t rack_probertt_use_min_rtt_exit = 0;
static uint32_t rack_probe_rtt_sets_cwnd = 0;
static uint32_t rack_probe_rtt_safety_val = 2000000;    /* No more than 2 sec in probe-rtt */
static uint32_t rack_time_between_probertt = 9600000;   /* 9.6 sec in usecs */
static uint32_t rack_probertt_gpsrtt_cnt_mul = 0;       /* How many srtt periods does probe-rtt last top fraction */
static uint32_t rack_probertt_gpsrtt_cnt_div = 0;       /* How many srtt periods does probe-rtt last bottom fraction */
static uint32_t rack_min_probertt_hold = 40000;         /* Equal to delayed ack time */
static uint32_t rack_probertt_filter_life = 10000000;
static uint32_t rack_probertt_lower_within = 10;
static uint32_t rack_min_rtt_movement = 250000; /* Must move at least 250ms (in microseconds)  to count as a lowering */
static int32_t rack_pace_one_seg = 0;           /* Shall we pace for less than 1.4Meg 1MSS at a time */
static int32_t rack_probertt_clear_is = 1;
static int32_t rack_max_drain_hbp = 1;          /* Extra drain times gpsrtt for highly buffered paths */
static int32_t rack_hbp_thresh = 3;             /* what is the divisor max_rtt/min_rtt to decided a hbp */

/* Part of pacing */
static int32_t rack_max_per_above = 30;         /* When we go to increment stop if above 100+this% */

/* Timely information:
 *
 * Here we have various control parameters on how
 * timely may change the multiplier. rack_gain_p5_ub
 * is associated with timely but not directly influencing
 * the rate decision like the other variables. It controls
 * the way fill-cw interacts with timely and caps how much
 * timely can boost the fill-cw b/w.
 *
 * The other values are various boost/shrink numbers as well
 * as potential caps when adjustments are made to the timely
 * gain (returned by rack_get_output_gain(). Remember too that
 * the gain returned can be overriden by other factors such as
 * probeRTT as well as fixed-rate-pacing.
 */
static int32_t rack_gain_p5_ub = 250;
static int32_t rack_gp_per_bw_mul_up = 2;       /* 2% */
static int32_t rack_gp_per_bw_mul_down = 4;     /* 4% */
static int32_t rack_gp_rtt_maxmul = 3;          /* 3 x maxmin */
static int32_t rack_gp_rtt_minmul = 1;          /* minrtt + (minrtt/mindiv) is lower rtt */
static int32_t rack_gp_rtt_mindiv = 4;          /* minrtt + (minrtt * minmul/mindiv) is lower rtt */
static int32_t rack_gp_decrease_per = 80;       /* Beta value of timely decrease (.8) = 80 */
static int32_t rack_gp_increase_per = 2;        /* 2% increase in multiplier */
static int32_t rack_per_lower_bound = 50;       /* Don't allow to drop below this multiplier */
static int32_t rack_per_upper_bound_ss = 0;     /* Don't allow SS to grow above this */
static int32_t rack_per_upper_bound_ca = 0;     /* Don't allow CA to grow above this */
static int32_t rack_do_dyn_mul = 0;             /* Are the rack gp multipliers dynamic */
static int32_t rack_gp_no_rec_chg = 1;          /* Prohibit recovery from reducing it's multiplier */
static int32_t rack_timely_dec_clear = 6;       /* Do we clear decrement count at a value (6)? */
static int32_t rack_timely_max_push_rise = 3;   /* One round of pushing */
static int32_t rack_timely_max_push_drop = 3;   /* Three round of pushing */
static int32_t rack_timely_min_segs = 4;        /* 4 segment minimum */
static int32_t rack_timely_no_stopping = 0;
static int32_t rack_down_raise_thresh = 100;
static int32_t rack_req_segs = 1;
static uint64_t rack_bw_rate_cap = 0;
static uint64_t rack_fillcw_bw_cap = 3750000;   /* Cap fillcw at 30Mbps */


/* Rack specific counters */
counter_u64_t rack_saw_enobuf;
counter_u64_t rack_saw_enobuf_hw;
counter_u64_t rack_saw_enetunreach;
counter_u64_t rack_persists_sends;
counter_u64_t rack_persists_acks;
counter_u64_t rack_persists_loss;
counter_u64_t rack_persists_lost_ends;
counter_u64_t rack_total_bytes;
#ifdef INVARIANTS
counter_u64_t rack_adjust_map_bw;
#endif
/* Tail loss probe counters */
counter_u64_t rack_tlp_tot;
counter_u64_t rack_tlp_newdata;
counter_u64_t rack_tlp_retran;
counter_u64_t rack_tlp_retran_bytes;
counter_u64_t rack_to_tot;
counter_u64_t rack_hot_alloc;
counter_u64_t rack_to_alloc;
counter_u64_t rack_to_alloc_hard;
counter_u64_t rack_to_alloc_emerg;
counter_u64_t rack_to_alloc_limited;
counter_u64_t rack_alloc_limited_conns;
counter_u64_t rack_split_limited;
counter_u64_t rack_rxt_clamps_cwnd;
counter_u64_t rack_rxt_clamps_cwnd_uniq;

counter_u64_t rack_multi_single_eq;
counter_u64_t rack_proc_non_comp_ack;

counter_u64_t rack_fto_send;
counter_u64_t rack_fto_rsm_send;
counter_u64_t rack_nfto_resend;
counter_u64_t rack_non_fto_send;
counter_u64_t rack_extended_rfo;

counter_u64_t rack_sack_proc_all;
counter_u64_t rack_sack_proc_short;
counter_u64_t rack_sack_proc_restart;

counter_u64_t rack_input_idle_reduces;
counter_u64_t rack_collapsed_win;
counter_u64_t rack_collapsed_win_seen;
counter_u64_t rack_collapsed_win_rxt;
counter_u64_t rack_collapsed_win_rxt_bytes;
counter_u64_t rack_try_scwnd;
counter_u64_t rack_hw_pace_init_fail;
counter_u64_t rack_hw_pace_lost;

counter_u64_t rack_out_size[TCP_MSS_ACCT_SIZE];
counter_u64_t rack_opts_arry[RACK_OPTS_SIZE];


#define RACK_REXMTVAL(tp) max(rack_rto_min, ((tp)->t_srtt + ((tp)->t_rttvar << 2)))

#define RACK_TCPT_RANGESET(tv, value, tvmin, tvmax, slop) do {  \
        (tv) = (value) + slop;   \
        if ((u_long)(tv) < (u_long)(tvmin)) \
                (tv) = (tvmin); \
        if ((u_long)(tv) > (u_long)(tvmax)) \
                (tv) = (tvmax); \
} while (0)

static void
rack_log_progress_event(struct tcp_rack *rack, struct tcpcb *tp, uint32_t tick,  int event, int line);

static int
rack_process_ack(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to,
    uint32_t tiwin, int32_t tlen, int32_t * ofia, int32_t thflags, int32_t * ret_val, int32_t orig_tlen);
static int
rack_process_data(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt);
static void
rack_ack_received(struct tcpcb *tp, struct tcp_rack *rack,
   uint32_t th_ack, uint16_t nsegs, uint16_t type, int32_t recovery);
static struct rack_sendmap *rack_alloc(struct tcp_rack *rack);
static struct rack_sendmap *rack_alloc_limit(struct tcp_rack *rack,
    uint8_t limit_type);
static struct rack_sendmap *
rack_check_recovery_mode(struct tcpcb *tp,
    uint32_t tsused);
static uint32_t
rack_grab_rtt(struct tcpcb *tp, struct tcp_rack *rack);
static void
rack_cong_signal(struct tcpcb *tp,
                 uint32_t type, uint32_t ack, int );
static void rack_counter_destroy(void);
static int
rack_ctloutput(struct tcpcb *tp, struct sockopt *sopt);
static int32_t rack_ctor(void *mem, int32_t size, void *arg, int32_t how);
static void
rack_set_pace_segments(struct tcpcb *tp, struct tcp_rack *rack, uint32_t line, uint64_t *fill_override);
static void
rack_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
    int32_t drop_hdrlen, int32_t tlen, uint8_t iptos);
static void rack_dtor(void *mem, int32_t size, void *arg);
static void
rack_log_alt_to_to_cancel(struct tcp_rack *rack,
    uint32_t flex1, uint32_t flex2,
    uint32_t flex3, uint32_t flex4,
    uint32_t flex5, uint32_t flex6,
    uint16_t flex7, uint8_t mod);

static void
rack_log_pacing_delay_calc(struct tcp_rack *rack, uint32_t len, uint32_t pacing_delay,
   uint64_t bw_est, uint64_t bw, uint64_t len_time, int method, int line,
   struct rack_sendmap *rsm, uint8_t quality);
static struct rack_sendmap *
rack_find_high_nonack(struct tcp_rack *rack,
    struct rack_sendmap *rsm);
static struct rack_sendmap *rack_find_lowest_rsm(struct tcp_rack *rack);
static void rack_free(struct tcp_rack *rack, struct rack_sendmap *rsm);
static void rack_fini(struct tcpcb *tp, int32_t tcb_is_purged);
static int rack_get_sockopt(struct tcpcb *tp, struct sockopt *sopt);
static void
rack_do_goodput_measurement(struct tcpcb *tp, struct tcp_rack *rack,
                            tcp_seq th_ack, int line, uint8_t quality);
static void
rack_log_type_pacing_sizes(struct tcpcb *tp, struct tcp_rack *rack, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint8_t frm);

static uint32_t
rack_get_pacing_len(struct tcp_rack *rack, uint64_t bw, uint32_t mss);
static int32_t rack_handoff_ok(struct tcpcb *tp);
static int32_t rack_init(struct tcpcb *tp, void **ptr);
static void rack_init_sysctls(void);

static void
rack_log_ack(struct tcpcb *tp, struct tcpopt *to,
    struct tcphdr *th, int entered_rec, int dup_ack_struck,
    int *dsack_seen, int *sacks_seen);
static void
rack_log_output(struct tcpcb *tp, struct tcpopt *to, int32_t len,
    uint32_t seq_out, uint16_t th_flags, int32_t err, uint64_t ts,
    struct rack_sendmap *hintrsm, uint32_t add_flags, struct mbuf *s_mb, uint32_t s_moff, int hw_tls, int segsiz);

static uint64_t rack_get_gp_est(struct tcp_rack *rack);


static void
rack_log_sack_passed(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, uint32_t cts, int line);
static void rack_log_to_event(struct tcp_rack *rack, int32_t to_num, struct rack_sendmap *rsm);
static int32_t rack_output(struct tcpcb *tp);

static uint32_t
rack_proc_sack_blk(struct tcpcb *tp, struct tcp_rack *rack,
    struct sackblk *sack, struct tcpopt *to, struct rack_sendmap **prsm,
    uint32_t cts, uint32_t segsiz);
static void rack_post_recovery(struct tcpcb *tp, uint32_t th_seq);
static void rack_remxt_tmr(struct tcpcb *tp);
static int rack_set_sockopt(struct tcpcb *tp, struct sockopt *sopt);
static void rack_set_state(struct tcpcb *tp, struct tcp_rack *rack);
static int32_t rack_stopall(struct tcpcb *tp);
static void rack_timer_cancel(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts, int line);
static uint32_t
rack_update_entry(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, uint64_t ts, int32_t * lenp, uint32_t add_flag, int segsiz);
static void
rack_update_rsm(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, uint64_t ts, uint32_t add_flag, int segsiz);
static int
rack_update_rtt(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, struct tcpopt *to, uint32_t cts, int32_t ack_type, tcp_seq th_ack);
static int32_t tcp_addrack(module_t mod, int32_t type, void *data);
static int
rack_do_close_wait(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);

static int
rack_do_closing(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_established(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_fastnewdata(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_fin_wait_1(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_fin_wait_2(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_lastack(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_syn_recv(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static int
rack_do_syn_sent(struct mbuf *m, struct tcphdr *th,
    struct socket *so, struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen,
    int32_t tlen, uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos);
static void rack_chk_req_and_hybrid_on_out(struct tcp_rack *rack, tcp_seq seq, uint32_t len, uint64_t cts);
struct rack_sendmap *
tcp_rack_output(struct tcpcb *tp, struct tcp_rack *rack,
    uint32_t tsused);
static void tcp_rack_xmit_timer(struct tcp_rack *rack, int32_t rtt,
    uint32_t len, uint32_t us_tim, int confidence, struct rack_sendmap *rsm, uint16_t rtrcnt);
static void
     tcp_rack_partialack(struct tcpcb *tp);
static int
rack_set_profile(struct tcp_rack *rack, int prof);
static void
rack_apply_deferred_options(struct tcp_rack *rack);

int32_t rack_clear_counter=0;

static uint64_t
rack_get_lt_bw(struct tcp_rack *rack)
{
        struct timeval tv;
        uint64_t tim, bytes;

        tim = rack->r_ctl.lt_bw_time;
        bytes = rack->r_ctl.lt_bw_bytes;
        if (rack->lt_bw_up) {
                /* Include all the current bytes too */
                microuptime(&tv);
                bytes += (rack->rc_tp->snd_una - rack->r_ctl.lt_seq);
                tim += (tcp_tv_to_lusec(&tv) - rack->r_ctl.lt_timemark);
        }
        if ((bytes != 0) && (tim != 0))
                return ((bytes * (uint64_t)1000000) / tim);
        else
                return (0);
}

static void
rack_swap_beta_values(struct tcp_rack *rack, uint8_t flex8)
{
        struct sockopt sopt;
        struct cc_newreno_opts opt;
        struct tcpcb *tp;
        uint32_t old_beta;
        uint32_t old_beta_ecn;
        int error = 0, failed = 0;

        tp = rack->rc_tp;
        if (tp->t_cc == NULL) {
                /* Tcb is leaving */
                return;
        }
        rack->rc_pacing_cc_set = 1;
        if (strcmp(tp->t_cc->name, CCALGONAME_NEWRENO) != 0) {
                /* Not new-reno we can't play games with beta! */
                failed = 1;
                goto out;

        }
        if (CC_ALGO(tp)->ctl_output == NULL)  {
                /* Huh, not using new-reno so no swaps.? */
                failed = 2;
                goto out;
        }
        /* Get the current values out */
        sopt.sopt_valsize = sizeof(struct cc_newreno_opts);
        sopt.sopt_dir = SOPT_GET;
        opt.name = CC_NEWRENO_BETA;
        error = CC_ALGO(tp)->ctl_output(&tp->t_ccv, &sopt, &opt);
        if (error)  {
                failed = 3;
                goto out;
        }
        old_beta = opt.val;
        opt.name = CC_NEWRENO_BETA_ECN;
        error = CC_ALGO(tp)->ctl_output(&tp->t_ccv, &sopt, &opt);
        if (error)  {
                failed = 4;
                goto out;
        }
        old_beta_ecn = opt.val;

        /* Now lets set in the values we have stored */
        sopt.sopt_dir = SOPT_SET;
        opt.name = CC_NEWRENO_BETA;
        opt.val = rack->r_ctl.rc_saved_beta;
        error = CC_ALGO(tp)->ctl_output(&tp->t_ccv, &sopt, &opt);
        if (error)  {
                failed = 5;
                goto out;
        }
        opt.name = CC_NEWRENO_BETA_ECN;
        opt.val = rack->r_ctl.rc_saved_beta_ecn;
        error = CC_ALGO(tp)->ctl_output(&tp->t_ccv, &sopt, &opt);
        if (error) {
                failed = 6;
                goto out;
        }
        /* Save off the values for restoral */
        rack->r_ctl.rc_saved_beta = old_beta;
        rack->r_ctl.rc_saved_beta_ecn = old_beta_ecn;
out:
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;
                struct newreno *ptr;

                ptr = ((struct newreno *)tp->t_ccv.cc_data);
                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex1 = ptr->beta;
                log.u_bbr.flex2 = ptr->beta_ecn;
                log.u_bbr.flex3 = ptr->newreno_flags;
                log.u_bbr.flex4 = rack->r_ctl.rc_saved_beta;
                log.u_bbr.flex5 = rack->r_ctl.rc_saved_beta_ecn;
                log.u_bbr.flex6 = failed;
                log.u_bbr.flex7 = rack->gp_ready;
                log.u_bbr.flex7 <<= 1;
                log.u_bbr.flex7 |= rack->use_fixed_rate;
                log.u_bbr.flex7 <<= 1;
                log.u_bbr.flex7 |= rack->rc_pacing_cc_set;
                log.u_bbr.pkts_out = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex8 = flex8;
                tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_CWND, error,
                               0, &log, false, NULL, NULL, 0, &tv);
        }
}

static void
rack_set_cc_pacing(struct tcp_rack *rack)
{
        if (rack->rc_pacing_cc_set)
                return;
        /*
         * Use the swap utility placing in 3 for flex8 to id a
         * set of a new set of values.
         */
        rack->rc_pacing_cc_set = 1;
        rack_swap_beta_values(rack, 3);
}

static void
rack_undo_cc_pacing(struct tcp_rack *rack)
{
        if (rack->rc_pacing_cc_set == 0)
                return;
        /*
         * Use the swap utility placing in 4 for flex8 to id a
         * restoral of the old values.
         */
        rack->rc_pacing_cc_set = 0;
        rack_swap_beta_values(rack, 4);
}

static void
rack_remove_pacing(struct tcp_rack *rack)
{
        if (rack->rc_pacing_cc_set)
                rack_undo_cc_pacing(rack);
        if (rack->r_ctl.pacing_method & RACK_REG_PACING)
                tcp_decrement_paced_conn();
        if (rack->r_ctl.pacing_method & RACK_DGP_PACING)
                tcp_dec_dgp_pacing_cnt();
        rack->rc_always_pace = 0;
        rack->r_ctl.pacing_method = RACK_PACING_NONE;
        rack->dgp_on = 0;
        rack->rc_hybrid_mode = 0;
        rack->use_fixed_rate = 0;
}

static void
rack_log_gpset(struct tcp_rack *rack, uint32_t seq_end, uint32_t ack_end_t,
               uint32_t send_end_t, int line, uint8_t mode, struct rack_sendmap *rsm)
{
        if (tcp_bblogging_on(rack->rc_tp) && (rack_verbose_logging != 0)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = seq_end;
                log.u_bbr.flex2 = rack->rc_tp->gput_seq;
                log.u_bbr.flex3 = ack_end_t;
                log.u_bbr.flex4 = rack->rc_tp->gput_ts;
                log.u_bbr.flex5 = send_end_t;
                log.u_bbr.flex6 = rack->rc_tp->gput_ack;
                log.u_bbr.flex7 = mode;
                log.u_bbr.flex8 = 69;
                log.u_bbr.rttProp = rack->r_ctl.rc_gp_cumack_ts;
                log.u_bbr.delRate = rack->r_ctl.rc_gp_output_ts;
                log.u_bbr.pkts_out = line;
                log.u_bbr.cwnd_gain = rack->app_limited_needs_set;
                log.u_bbr.pkt_epoch = rack->r_ctl.rc_app_limited_cnt;
                log.u_bbr.epoch = rack->r_ctl.current_round;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_considered_lost;
                if (rsm != NULL) {
                        log.u_bbr.applimited = rsm->r_start;
                        log.u_bbr.delivered = rsm->r_end;
                        log.u_bbr.epoch = rsm->r_flags;
                }
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_HPTSI_CALC, 0,
                    0, &log, false, &tv);
        }
}

static int
sysctl_rack_clear(SYSCTL_HANDLER_ARGS)
{
        uint32_t stat;
        int32_t error;

        error = SYSCTL_OUT(req, &rack_clear_counter, sizeof(uint32_t));
        if (error || req->newptr == NULL)
                return error;

        error = SYSCTL_IN(req, &stat, sizeof(uint32_t));
        if (error)
                return (error);
        if (stat == 1) {
#ifdef INVARIANTS
                printf("Clearing RACK counters\n");
#endif
                counter_u64_zero(rack_tlp_tot);
                counter_u64_zero(rack_tlp_newdata);
                counter_u64_zero(rack_tlp_retran);
                counter_u64_zero(rack_tlp_retran_bytes);
                counter_u64_zero(rack_to_tot);
                counter_u64_zero(rack_saw_enobuf);
                counter_u64_zero(rack_saw_enobuf_hw);
                counter_u64_zero(rack_saw_enetunreach);
                counter_u64_zero(rack_persists_sends);
                counter_u64_zero(rack_total_bytes);
                counter_u64_zero(rack_persists_acks);
                counter_u64_zero(rack_persists_loss);
                counter_u64_zero(rack_persists_lost_ends);
#ifdef INVARIANTS
                counter_u64_zero(rack_adjust_map_bw);
#endif
                counter_u64_zero(rack_to_alloc_hard);
                counter_u64_zero(rack_to_alloc_emerg);
                counter_u64_zero(rack_sack_proc_all);
                counter_u64_zero(rack_fto_send);
                counter_u64_zero(rack_fto_rsm_send);
                counter_u64_zero(rack_extended_rfo);
                counter_u64_zero(rack_hw_pace_init_fail);
                counter_u64_zero(rack_hw_pace_lost);
                counter_u64_zero(rack_non_fto_send);
                counter_u64_zero(rack_nfto_resend);
                counter_u64_zero(rack_sack_proc_short);
                counter_u64_zero(rack_sack_proc_restart);
                counter_u64_zero(rack_to_alloc);
                counter_u64_zero(rack_to_alloc_limited);
                counter_u64_zero(rack_alloc_limited_conns);
                counter_u64_zero(rack_split_limited);
                counter_u64_zero(rack_rxt_clamps_cwnd);
                counter_u64_zero(rack_rxt_clamps_cwnd_uniq);
                counter_u64_zero(rack_multi_single_eq);
                counter_u64_zero(rack_proc_non_comp_ack);
                counter_u64_zero(rack_try_scwnd);
                counter_u64_zero(rack_collapsed_win);
                counter_u64_zero(rack_collapsed_win_rxt);
                counter_u64_zero(rack_collapsed_win_seen);
                counter_u64_zero(rack_collapsed_win_rxt_bytes);
        } else if (stat == 2) {
#ifdef INVARIANTS
                printf("Clearing RACK option array\n");
#endif
                COUNTER_ARRAY_ZERO(rack_opts_arry, RACK_OPTS_SIZE);
        } else if (stat == 3) {
                printf("Rack has no stats counters to clear (use 1 to clear all stats in sysctl node)\n");
        } else if (stat == 4) {
#ifdef INVARIANTS
                printf("Clearing RACK out size array\n");
#endif
                COUNTER_ARRAY_ZERO(rack_out_size, TCP_MSS_ACCT_SIZE);
        }
        rack_clear_counter = 0;
        return (0);
}

static void
rack_init_sysctls(void)
{
        struct sysctl_oid *rack_counters;
        struct sysctl_oid *rack_pacing;
        struct sysctl_oid *rack_timely;
        struct sysctl_oid *rack_timers;
        struct sysctl_oid *rack_tlp;
        struct sysctl_oid *rack_misc;
        struct sysctl_oid *rack_features;
        struct sysctl_oid *rack_measure;
        struct sysctl_oid *rack_probertt;
        struct sysctl_oid *rack_hw_pacing;

        rack_counters = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "stats",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Rack Counters");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO, "rate_sample_method", CTLFLAG_RW,
            &rack_rate_sample_method , USE_RTT_LOW,
            "What method should we use for rate sampling 0=high, 1=low ");
        /* Probe rtt related controls */
        rack_probertt = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "probertt",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "ProbeRTT related Controls");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "exit_per_hpb", CTLFLAG_RW,
            &rack_atexit_prtt_hbp, 130,
            "What percentage above goodput do we clamp CA/SS to at exit on high-BDP path 110%");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "exit_per_nonhpb", CTLFLAG_RW,
            &rack_atexit_prtt, 130,
            "What percentage above goodput do we clamp CA/SS to at exit on a non high-BDP path 100%");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "gp_per_mul", CTLFLAG_RW,
            &rack_per_of_gp_probertt, 60,
            "What percentage of goodput do we pace at in probertt");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "gp_per_reduce", CTLFLAG_RW,
            &rack_per_of_gp_probertt_reduce, 10,
            "What percentage of goodput do we reduce every gp_srtt");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "gp_per_low", CTLFLAG_RW,
            &rack_per_of_gp_lowthresh, 40,
            "What percentage of goodput do we allow the multiplier to fall to");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "time_between", CTLFLAG_RW,
            &rack_time_between_probertt, 96000000,
            "How many useconds between the lowest rtt falling must past before we enter probertt");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "safety", CTLFLAG_RW,
            &rack_probe_rtt_safety_val, 2000000,
            "If not zero, provides a maximum usecond that you can stay in probertt (2sec = 2000000)");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "sets_cwnd", CTLFLAG_RW,
            &rack_probe_rtt_sets_cwnd, 0,
            "Do we set the cwnd too (if always_lower is on)");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "maxdrainsrtts", CTLFLAG_RW,
            &rack_max_drain_wait, 2,
            "Maximum number of gp_srtt's to hold in drain waiting for flight to reach goal");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "mustdrainsrtts", CTLFLAG_RW,
            &rack_must_drain, 1,
            "We must drain this many gp_srtt's waiting for flight to reach goal");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "goal_use_min_entry", CTLFLAG_RW,
            &rack_probertt_use_min_rtt_entry, 1,
            "Should we use the min-rtt to calculate the goal rtt (else gp_srtt) at entry");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "goal_use_min_exit", CTLFLAG_RW,
            &rack_probertt_use_min_rtt_exit, 0,
            "How to set cwnd at exit, 0 - dynamic, 1 - use min-rtt, 2 - use curgprtt, 3 - entry gp-rtt");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "length_div", CTLFLAG_RW,
            &rack_probertt_gpsrtt_cnt_div, 0,
            "How many recent goodput srtt periods plus hold tim does probertt last (bottom of fraction)");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "length_mul", CTLFLAG_RW,
            &rack_probertt_gpsrtt_cnt_mul, 0,
            "How many recent goodput srtt periods plus hold tim does probertt last (top of fraction)");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "holdtim_at_target", CTLFLAG_RW,
            &rack_min_probertt_hold, 200000,
            "What is the minimum time we hold probertt at target");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "filter_life", CTLFLAG_RW,
            &rack_probertt_filter_life, 10000000,
            "What is the time for the filters life in useconds");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "lower_within", CTLFLAG_RW,
            &rack_probertt_lower_within, 10,
            "If the rtt goes lower within this percentage of the time, go into probe-rtt");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "must_move", CTLFLAG_RW,
            &rack_min_rtt_movement, 250,
            "How much is the minimum movement in rtt to count as a drop for probertt purposes");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "clear_is_cnts", CTLFLAG_RW,
            &rack_probertt_clear_is, 1,
            "Do we clear I/S counts on exiting probe-rtt");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "hbp_extra_drain", CTLFLAG_RW,
            &rack_max_drain_hbp, 1,
            "How many extra drain gpsrtt's do we get in highly buffered paths");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_probertt),
            OID_AUTO, "hbp_threshold", CTLFLAG_RW,
            &rack_hbp_thresh, 3,
            "We are highly buffered if min_rtt_seen / max_rtt_seen > this-threshold");
        /* Pacing related sysctls */
        rack_pacing = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "pacing",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Pacing related Controls");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "pcm_enabled", CTLFLAG_RW,
            &rack_pcm_is_enabled, 1,
            "Do we by default do PCM measurements?");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "pcm_rnds", CTLFLAG_RW,
            &rack_pcm_every_n_rounds, 100,
            "How many rounds before we need to do a PCM measurement");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "pcm_blast", CTLFLAG_RW,
            &rack_pcm_blast, 0,
            "Blast out the full cwnd/rwnd when doing a PCM measurement");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "rnd_gp_gain", CTLFLAG_RW,
            &rack_gp_gain_req, 1200,
            "How much do we have to increase the GP to record the round 1200 = 120.0");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "dgp_out_of_ss_at", CTLFLAG_RW,
            &rack_rnd_cnt_req, 0x10005,
            "How many rounds less than rnd_gp_gain will drop us out of SS");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "no_timely", CTLFLAG_RW,
            &rack_timely_off, 0,
            "Do we not use timely in DGP?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "fillcw", CTLFLAG_RW,
            &rack_fill_cw_state, 0,
            "Enable fillcw on new connections (default=0 off)?");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "min_burst", CTLFLAG_RW,
            &rack_pacing_min_seg, 0,
            "What is the min burst size for pacing (0 disables)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "divisor", CTLFLAG_RW,
            &rack_default_pacing_divisor, 250,
            "What is the default divisor given to the rl code?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "fillcw_max_mult", CTLFLAG_RW,
            &rack_bw_multipler, 0,
            "What is the limit multiplier of the current gp_est that fillcw can increase the b/w too, 200 == 200% (0 = off)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "max_pace_over", CTLFLAG_RW,
            &rack_max_per_above, 30,
            "What is the maximum allowable percentage that we can pace above (so 30 = 130% of our goal)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "allow1mss", CTLFLAG_RW,
            &rack_pace_one_seg, 0,
            "Do we allow low b/w pacing of 1MSS instead of two (1.2Meg and less)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "limit_wsrtt", CTLFLAG_RW,
            &rack_limit_time_with_srtt, 0,
            "Do we limit pacing time based on srtt");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "gp_per_ss", CTLFLAG_RW,
            &rack_per_of_gp_ss, 250,
            "If non zero, what percentage of goodput to pace at in slow start");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "gp_per_ca", CTLFLAG_RW,
            &rack_per_of_gp_ca, 150,
            "If non zero, what percentage of goodput to pace at in congestion avoidance");
        SYSCTL_ADD_U16(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "gp_per_rec", CTLFLAG_RW,
            &rack_per_of_gp_rec, 200,
            "If non zero, what percentage of goodput to pace at in recovery");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "pace_max_seg", CTLFLAG_RW,
            &rack_hptsi_segments, 40,
            "What size is the max for TSO segments in pacing and burst mitigation");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "burst_reduces", CTLFLAG_RW,
            &rack_pacing_delay_reduction, 4,
            "When doing only burst mitigation what is the reduce divisor");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO, "use_pacing", CTLFLAG_RW,
            &rack_pace_every_seg, 0,
            "If set we use pacing, if clear we use only the original burst mitigation");
        SYSCTL_ADD_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "rate_cap", CTLFLAG_RW,
            &rack_bw_rate_cap, 0,
            "If set we apply this value to the absolute rate cap used by pacing");
        SYSCTL_ADD_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_pacing),
            OID_AUTO, "fillcw_cap", CTLFLAG_RW,
            &rack_fillcw_bw_cap, 3750000,
            "Do we have an absolute cap on the amount of b/w fillcw can specify (0 = no)?");
        SYSCTL_ADD_U8(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO, "req_measure_cnt", CTLFLAG_RW,
            &rack_req_measurements, 1,
            "If doing dynamic pacing, how many measurements must be in before we start pacing?");
        /* Hardware pacing */
        rack_hw_pacing = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "hdwr_pacing",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Pacing related Controls");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "rwnd_factor", CTLFLAG_RW,
            &rack_hw_rwnd_factor, 2,
            "How many times does snd_wnd need to be bigger than pace_max_seg so we will hold off and get more acks?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "precheck", CTLFLAG_RW,
            &rack_hw_check_queue, 0,
            "Do we always precheck the hdwr pacing queue to avoid ENOBUF's?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "pace_enobuf_mult", CTLFLAG_RW,
            &rack_enobuf_hw_boost_mult, 0,
            "By how many time_betweens should we boost the pacing time if we see a ENOBUFS?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "pace_enobuf_max", CTLFLAG_RW,
            &rack_enobuf_hw_max, 2,
            "What is the max boost the pacing time if we see a ENOBUFS?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "pace_enobuf_min", CTLFLAG_RW,
            &rack_enobuf_hw_min, 2,
            "What is the min boost the pacing time if we see a ENOBUFS?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "enable", CTLFLAG_RW,
            &rack_enable_hw_pacing, 0,
            "Should RACK attempt to use hw pacing?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "rate_cap", CTLFLAG_RW,
            &rack_hw_rate_caps, 0,
            "Does the highest hardware pacing rate cap the rate we will send at??");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "uncap_per", CTLFLAG_RW,
            &rack_hw_rate_cap_per, 0,
            "If you go over b/w by this amount you will be uncapped (0 = never)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "rate_min", CTLFLAG_RW,
            &rack_hw_rate_min, 0,
            "Do we need a minimum estimate of this many bytes per second in order to engage hw pacing?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "rate_to_low", CTLFLAG_RW,
            &rack_hw_rate_to_low, 0,
            "If we fall below this rate, dis-engage hw pacing?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_hw_pacing),
            OID_AUTO, "up_only", CTLFLAG_RW,
            &rack_hw_up_only, 0,
            "Do we allow hw pacing to lower the rate selected?");
        rack_timely = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "timely",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Rack Timely RTT Controls");
        /* Timely based GP dynmics */
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "upper", CTLFLAG_RW,
            &rack_gp_per_bw_mul_up, 2,
            "Rack timely upper range for equal b/w (in percentage)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "lower", CTLFLAG_RW,
            &rack_gp_per_bw_mul_down, 4,
            "Rack timely lower range for equal b/w (in percentage)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "rtt_max_mul", CTLFLAG_RW,
            &rack_gp_rtt_maxmul, 3,
            "Rack timely multiplier of lowest rtt for rtt_max");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "rtt_min_div", CTLFLAG_RW,
            &rack_gp_rtt_mindiv, 4,
            "Rack timely divisor used for rtt + (rtt * mul/divisor) for check for lower rtt");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "rtt_min_mul", CTLFLAG_RW,
            &rack_gp_rtt_minmul, 1,
            "Rack timely multiplier used for rtt + (rtt * mul/divisor) for check for lower rtt");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "decrease", CTLFLAG_RW,
            &rack_gp_decrease_per, 80,
            "Rack timely Beta value 80 = .8 (scaled by 100)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "increase", CTLFLAG_RW,
            &rack_gp_increase_per, 2,
            "Rack timely increase perentage of our GP multiplication factor");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "lowerbound", CTLFLAG_RW,
            &rack_per_lower_bound, 50,
            "Rack timely lowest percentage we allow GP multiplier to fall to");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "p5_upper", CTLFLAG_RW,
            &rack_gain_p5_ub, 250,
            "Profile 5 upper bound to timely gain");

        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "upperboundss", CTLFLAG_RW,
            &rack_per_upper_bound_ss, 0,
            "Rack timely highest percentage we allow GP multiplier in SS to raise to (0 is no upperbound)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "upperboundca", CTLFLAG_RW,
            &rack_per_upper_bound_ca, 0,
            "Rack timely highest percentage we allow GP multiplier to CA raise to (0 is no upperbound)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "dynamicgp", CTLFLAG_RW,
            &rack_do_dyn_mul, 0,
            "Rack timely do we enable dynmaic timely goodput by default");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "no_rec_red", CTLFLAG_RW,
            &rack_gp_no_rec_chg, 1,
            "Rack timely do we prohibit the recovery multiplier from being lowered");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "red_clear_cnt", CTLFLAG_RW,
            &rack_timely_dec_clear, 6,
            "Rack timely what threshold do we count to before another boost during b/w decent");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "max_push_rise", CTLFLAG_RW,
            &rack_timely_max_push_rise, 3,
            "Rack timely how many times do we push up with b/w increase");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "max_push_drop", CTLFLAG_RW,
            &rack_timely_max_push_drop, 3,
            "Rack timely how many times do we push back on b/w decent");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "min_segs", CTLFLAG_RW,
            &rack_timely_min_segs, 4,
            "Rack timely when setting the cwnd what is the min num segments");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "nonstop", CTLFLAG_RW,
            &rack_timely_no_stopping, 0,
            "Rack timely don't stop increase");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "dec_raise_thresh", CTLFLAG_RW,
            &rack_down_raise_thresh, 100,
            "If the CA or SS is below this threshold raise on the first 3 b/w lowers (0=always)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timely),
            OID_AUTO, "bottom_drag_segs", CTLFLAG_RW,
            &rack_req_segs, 1,
            "Bottom dragging if not these many segments outstanding and room");

        /* TLP and Rack related parameters */
        rack_tlp = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "tlp",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "TLP and Rack related Controls");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "use_rrr", CTLFLAG_RW,
            &use_rack_rr, 1,
            "Do we use Rack Rapid Recovery");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "post_rec_labc", CTLFLAG_RW,
            &rack_max_abc_post_recovery, 2,
            "Since we do early recovery, do we override the l_abc to a value, if so what?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "nonrxt_use_cr", CTLFLAG_RW,
            &rack_non_rxt_use_cr, 0,
            "Do we use ss/ca rate if in recovery we are transmitting a new data chunk");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "tlpmethod", CTLFLAG_RW,
            &rack_tlp_threshold_use, TLP_USE_TWO_ONE,
            "What method do we do for TLP time calc 0=no-de-ack-comp, 1=ID, 2=2.1, 3=2.2");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "limit", CTLFLAG_RW,
            &rack_tlp_limit, 2,
            "How many TLP's can be sent without sending new data");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "use_greater", CTLFLAG_RW,
            &rack_tlp_use_greater, 1,
            "Should we use the rack_rtt time if its greater than srtt");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "tlpminto", CTLFLAG_RW,
            &rack_tlp_min, 10000,
            "TLP minimum timeout per the specification (in microseconds)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "send_oldest", CTLFLAG_RW,
            &rack_always_send_oldest, 0,
            "Should we always send the oldest TLP and RACK-TLP");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "tlp_cwnd_flag", CTLFLAG_RW,
            &rack_lower_cwnd_at_tlp, 0,
            "When a TLP completes a retran should we enter recovery");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "reorder_thresh", CTLFLAG_RW,
            &rack_reorder_thresh, 2,
            "What factor for rack will be added when seeing reordering (shift right)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "rtt_tlp_thresh", CTLFLAG_RW,
            &rack_tlp_thresh, 1,
            "What divisor for TLP rtt/retran will be added (1=rtt, 2=1/2 rtt etc)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "reorder_fade", CTLFLAG_RW,
            &rack_reorder_fade, 60000000,
            "Does reorder detection fade, if so how many microseconds (0 means never)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_tlp),
            OID_AUTO, "pktdelay", CTLFLAG_RW,
            &rack_pkt_delay, 1000,
            "Extra RACK time (in microseconds) besides reordering thresh");

        /* Timer related controls */
        rack_timers = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "timers",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Timer related controls");
        SYSCTL_ADD_U8(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "reset_ssth_rec_rto", CTLFLAG_RW,
            &rack_ssthresh_rest_rto_rec, 0,
            "When doing recovery -> rto -> recovery do we reset SSthresh?");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "rtt_divisor", CTLFLAG_RW,
            &rack_rtt_divisor, 2,
            "When calculating the rtt threshold what 1/N is a rtt that indicates reordering");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "scoreboard_thresh", CTLFLAG_RW,
            &rack_rxt_scoreboard_clear_thresh, 2,
            "How many RTO's are allowed before we clear the scoreboard");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "honor_hpts_min", CTLFLAG_RW,
            &rack_honors_hpts_min_to, 1,
            "Do rack pacing timers honor hpts min timeout");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "hpts_max_reduce", CTLFLAG_RW,
            &rack_max_reduce, 10,
            "Max percentage we will reduce pacing delay by for pacing when we are behind");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "persmin", CTLFLAG_RW,
            &rack_persist_min, 250000,
            "What is the minimum time in microseconds between persists");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "persmax", CTLFLAG_RW,
            &rack_persist_max, 2000000,
            "What is the largest delay in microseconds between persists");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "delayed_ack", CTLFLAG_RW,
            &rack_delayed_ack_time, 40000,
            "Delayed ack time (40ms in microseconds)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "minrto", CTLFLAG_RW,
            &rack_rto_min, 30000,
            "Minimum RTO in microseconds -- set with caution below 1000 due to TLP");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "maxrto", CTLFLAG_RW,
            &rack_rto_max, 4000000,
            "Maximum RTO in microseconds -- should be at least as large as min_rto");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_timers),
            OID_AUTO, "minto", CTLFLAG_RW,
            &rack_min_to, 1000,
            "Minimum rack timeout in microseconds");
        /* Measure controls */
        rack_measure = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "measure",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Measure related controls");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "wma_divisor", CTLFLAG_RW,
            &rack_wma_divisor, 8,
            "When doing b/w calculation what is the  divisor for the WMA");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "end_cwnd", CTLFLAG_RW,
            &rack_cwnd_block_ends_measure, 0,
            "Does a cwnd just-return end the measurement window (app limited)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "end_rwnd", CTLFLAG_RW,
            &rack_rwnd_block_ends_measure, 0,
            "Does an rwnd just-return end the measurement window (app limited -- not persists)");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "min_target", CTLFLAG_RW,
            &rack_def_data_window, 20,
            "What is the minimum target window (in mss) for a GP measurements");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "goal_bdp", CTLFLAG_RW,
            &rack_goal_bdp, 2,
            "What is the goal BDP to measure");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "min_srtts", CTLFLAG_RW,
            &rack_min_srtts, 1,
            "What is the goal BDP to measure");
        SYSCTL_ADD_U32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_measure),
            OID_AUTO, "min_measure_tim", CTLFLAG_RW,
            &rack_min_measure_usec, 0,
            "What is the Minimum time time for a measurement if 0, this is off");
        /* Features */
        rack_features = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "features",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Feature controls");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "hybrid_set_maxseg", CTLFLAG_RW,
            &rack_hybrid_allow_set_maxseg, 0,
            "Should hybrid pacing allow the setmss command");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "cmpack", CTLFLAG_RW,
            &rack_use_cmp_acks, 1,
            "Should RACK have LRO send compressed acks");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "fsb", CTLFLAG_RW,
            &rack_use_fsb, 1,
            "Should RACK use the fast send block?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "rfo", CTLFLAG_RW,
            &rack_use_rfo, 1,
            "Should RACK use rack_fast_output()?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "rsmrfo", CTLFLAG_RW,
            &rack_use_rsm_rfo, 1,
            "Should RACK use rack_fast_rsm_output()?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "non_paced_lro_queue", CTLFLAG_RW,
            &rack_enable_mqueue_for_nonpaced, 0,
            "Should RACK use mbuf queuing for non-paced connections");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_features),
            OID_AUTO, "hystartplusplus", CTLFLAG_RW,
            &rack_do_hystart, 0,
            "Should RACK enable HyStart++ on connections?");
        /* Misc rack controls */
        rack_misc = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO,
            "misc",
            CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
            "Misc related controls");
#ifdef TCP_ACCOUNTING
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "tcp_acct", CTLFLAG_RW,
            &rack_tcp_accounting, 0,
            "Should we turn on TCP accounting for all rack sessions?");
#endif
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "dnd", CTLFLAG_RW,
            &rack_dnd_default, 0,
            "Do not disturb default for rack_rrr = 3");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "rxt_controls", CTLFLAG_RW,
            &rack_rxt_controls, 0,
            "Retransmit sending size controls (valid  values 0, 1, 2 default=1)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "rack_hibeta", CTLFLAG_RW,
            &rack_hibeta_setting, 0,
            "Do we ue a high beta (80 instead of 50)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "apply_rtt_with_low_conf", CTLFLAG_RW,
            &rack_apply_rtt_with_reduced_conf, 0,
            "When a persist or keep-alive probe is not answered do we calculate rtt on subsequent answers?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "rack_dsack_ctl", CTLFLAG_RW,
            &rack_dsack_std_based, 3,
            "How do we process dsack with respect to rack timers, bit field, 3 is standards based?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "prr_addback_max", CTLFLAG_RW,
            &rack_prr_addbackmax, 2,
            "What is the maximum number of MSS we allow to be added back if prr can't send all its data?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "stats_gets_ms", CTLFLAG_RW,
            &rack_stats_gets_ms_rtt, 1,
            "What do we feed the stats framework (1 = ms_rtt, 0 = us_rtt, 2 = ms_rtt from hdwr, > 2 usec rtt from hdwr)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "clientlowbuf", CTLFLAG_RW,
            &rack_client_low_buf, 0,
            "Client low buffer level (below this we are more aggressive in DGP exiting recovery (0 = off)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "defprofile", CTLFLAG_RW,
            &rack_def_profile, 0,
            "Should RACK use a default profile (0=no, num == profile num)?");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "shared_cwnd", CTLFLAG_RW,
            &rack_enable_shared_cwnd, 1,
            "Should RACK try to use the shared cwnd on connections where allowed");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "limits_on_scwnd", CTLFLAG_RW,
            &rack_limits_scwnd, 1,
            "Should RACK place low end time limits on the shared cwnd feature");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "no_prr", CTLFLAG_RW,
            &rack_disable_prr, 0,
            "Should RACK not use prr and only pace (must have pacing on)");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "bb_verbose", CTLFLAG_RW,
            &rack_verbose_logging, 0,
            "Should RACK black box logging be verbose");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "data_after_close", CTLFLAG_RW,
            &rack_ignore_data_after_close, 1,
            "Do we hold off sending a RST until all pending data is ack'd");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "no_sack_needed", CTLFLAG_RW,
            &rack_sack_not_required, 1,
            "Do we allow rack to run on connections not supporting SACK");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "prr_sendalot", CTLFLAG_RW,
            &rack_send_a_lot_in_prr, 1,
            "Send a lot in prr");
        SYSCTL_ADD_S32(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_misc),
            OID_AUTO, "autoscale", CTLFLAG_RW,
            &rack_autosndbuf_inc, 20,
            "What percentage should rack scale up its snd buffer by?");

        /* Counters */
        rack_total_bytes = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "totalbytes", CTLFLAG_RD,
            &rack_total_bytes,
            "Total number of bytes sent");
        rack_fto_send = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "fto_send", CTLFLAG_RD,
            &rack_fto_send, "Total number of rack_fast_output sends");
        rack_fto_rsm_send = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "fto_rsm_send", CTLFLAG_RD,
            &rack_fto_rsm_send, "Total number of rack_fast_rsm_output sends");
        rack_nfto_resend = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "nfto_resend", CTLFLAG_RD,
            &rack_nfto_resend, "Total number of rack_output retransmissions");
        rack_non_fto_send = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "nfto_send", CTLFLAG_RD,
            &rack_non_fto_send, "Total number of rack_output first sends");
        rack_extended_rfo = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "rfo_extended", CTLFLAG_RD,
            &rack_extended_rfo, "Total number of times we extended rfo");

        rack_hw_pace_init_fail = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "hwpace_init_fail", CTLFLAG_RD,
            &rack_hw_pace_init_fail, "Total number of times we failed to initialize hw pacing");
        rack_hw_pace_lost = counter_u64_alloc(M_WAITOK);

        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "hwpace_lost", CTLFLAG_RD,
            &rack_hw_pace_lost, "Total number of times we failed to initialize hw pacing");
        rack_tlp_tot = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "tlp_to_total", CTLFLAG_RD,
            &rack_tlp_tot,
            "Total number of tail loss probe expirations");
        rack_tlp_newdata = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "tlp_new", CTLFLAG_RD,
            &rack_tlp_newdata,
            "Total number of tail loss probe sending new data");
        rack_tlp_retran = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "tlp_retran", CTLFLAG_RD,
            &rack_tlp_retran,
            "Total number of tail loss probe sending retransmitted data");
        rack_tlp_retran_bytes = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "tlp_retran_bytes", CTLFLAG_RD,
            &rack_tlp_retran_bytes,
            "Total bytes of tail loss probe sending retransmitted data");
        rack_to_tot = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "rack_to_tot", CTLFLAG_RD,
            &rack_to_tot,
            "Total number of times the rack to expired");
        rack_saw_enobuf = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "saw_enobufs", CTLFLAG_RD,
            &rack_saw_enobuf,
            "Total number of times a sends returned enobuf for non-hdwr paced connections");
        rack_saw_enobuf_hw = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "saw_enobufs_hw", CTLFLAG_RD,
            &rack_saw_enobuf_hw,
            "Total number of times a send returned enobuf for hdwr paced connections");
        rack_saw_enetunreach = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "saw_enetunreach", CTLFLAG_RD,
            &rack_saw_enetunreach,
            "Total number of times a send received a enetunreachable");
        rack_hot_alloc = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "alloc_hot", CTLFLAG_RD,
            &rack_hot_alloc,
            "Total allocations from the top of our list");
        rack_to_alloc = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "allocs", CTLFLAG_RD,
            &rack_to_alloc,
            "Total allocations of tracking structures");
        rack_to_alloc_hard = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "allochard", CTLFLAG_RD,
            &rack_to_alloc_hard,
            "Total allocations done with sleeping the hard way");
        rack_to_alloc_emerg = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "allocemerg", CTLFLAG_RD,
            &rack_to_alloc_emerg,
            "Total allocations done from emergency cache");
        rack_to_alloc_limited = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "alloc_limited", CTLFLAG_RD,
            &rack_to_alloc_limited,
            "Total allocations dropped due to limit");
        rack_alloc_limited_conns = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "alloc_limited_conns", CTLFLAG_RD,
            &rack_alloc_limited_conns,
            "Connections with allocations dropped due to limit");
        rack_split_limited = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "split_limited", CTLFLAG_RD,
            &rack_split_limited,
            "Split allocations dropped due to limit");
        rack_rxt_clamps_cwnd = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "rxt_clamps_cwnd", CTLFLAG_RD,
            &rack_rxt_clamps_cwnd,
            "Number of times that excessive rxt clamped the cwnd down");
        rack_rxt_clamps_cwnd_uniq = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "rxt_clamps_cwnd_uniq", CTLFLAG_RD,
            &rack_rxt_clamps_cwnd_uniq,
            "Number of connections that have had excessive rxt clamped the cwnd down");
        rack_persists_sends = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "persist_sends", CTLFLAG_RD,
            &rack_persists_sends,
            "Number of times we sent a persist probe");
        rack_persists_acks = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "persist_acks", CTLFLAG_RD,
            &rack_persists_acks,
            "Number of times a persist probe was acked");
        rack_persists_loss = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "persist_loss", CTLFLAG_RD,
            &rack_persists_loss,
            "Number of times we detected a lost persist probe (no ack)");
        rack_persists_lost_ends = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "persist_loss_ends", CTLFLAG_RD,
            &rack_persists_lost_ends,
            "Number of lost persist probe (no ack) that the run ended with a PERSIST abort");
#ifdef INVARIANTS
        rack_adjust_map_bw = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "map_adjust_req", CTLFLAG_RD,
            &rack_adjust_map_bw,
            "Number of times we hit the case where the sb went up and down on a sendmap entry");
#endif
        rack_multi_single_eq = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "cmp_ack_equiv", CTLFLAG_RD,
            &rack_multi_single_eq,
            "Number of compressed acks total represented");
        rack_proc_non_comp_ack = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "cmp_ack_not", CTLFLAG_RD,
            &rack_proc_non_comp_ack,
            "Number of non compresseds acks that we processed");


        rack_sack_proc_all = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "sack_long", CTLFLAG_RD,
            &rack_sack_proc_all,
            "Total times we had to walk whole list for sack processing");
        rack_sack_proc_restart = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "sack_restart", CTLFLAG_RD,
            &rack_sack_proc_restart,
            "Total times we had to walk whole list due to a restart");
        rack_sack_proc_short = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "sack_short", CTLFLAG_RD,
            &rack_sack_proc_short,
            "Total times we took shortcut for sack processing");
        rack_input_idle_reduces = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "idle_reduce_oninput", CTLFLAG_RD,
            &rack_input_idle_reduces,
            "Total number of idle reductions on input");
        rack_collapsed_win_seen = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "collapsed_win_seen", CTLFLAG_RD,
            &rack_collapsed_win_seen,
            "Total number of collapsed window events seen (where our window shrinks)");

        rack_collapsed_win = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "collapsed_win", CTLFLAG_RD,
            &rack_collapsed_win,
            "Total number of collapsed window events where we mark packets");
        rack_collapsed_win_rxt = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "collapsed_win_rxt", CTLFLAG_RD,
            &rack_collapsed_win_rxt,
            "Total number of packets that were retransmitted");
        rack_collapsed_win_rxt_bytes = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "collapsed_win_bytes", CTLFLAG_RD,
            &rack_collapsed_win_rxt_bytes,
            "Total number of bytes that were retransmitted");
        rack_try_scwnd = counter_u64_alloc(M_WAITOK);
        SYSCTL_ADD_COUNTER_U64(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_counters),
            OID_AUTO, "tried_scwnd", CTLFLAG_RD,
            &rack_try_scwnd,
            "Total number of scwnd attempts");
        COUNTER_ARRAY_ALLOC(rack_out_size, TCP_MSS_ACCT_SIZE, M_WAITOK);
        SYSCTL_ADD_COUNTER_U64_ARRAY(&rack_sysctl_ctx, SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO, "outsize", CTLFLAG_RD,
            rack_out_size, TCP_MSS_ACCT_SIZE, "MSS send sizes");
        COUNTER_ARRAY_ALLOC(rack_opts_arry, RACK_OPTS_SIZE, M_WAITOK);
        SYSCTL_ADD_COUNTER_U64_ARRAY(&rack_sysctl_ctx, SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO, "opts", CTLFLAG_RD,
            rack_opts_arry, RACK_OPTS_SIZE, "RACK Option Stats");
        SYSCTL_ADD_PROC(&rack_sysctl_ctx,
            SYSCTL_CHILDREN(rack_sysctl_root),
            OID_AUTO, "clear", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
            &rack_clear_counter, 0, sysctl_rack_clear, "IU", "Clear counters");
}

static uint32_t
rc_init_window(struct tcp_rack *rack)
{
        return (tcp_compute_initwnd(tcp_maxseg(rack->rc_tp)));

}

static uint64_t
rack_get_fixed_pacing_bw(struct tcp_rack *rack)
{
        if (IN_FASTRECOVERY(rack->rc_tp->t_flags))
                return (rack->r_ctl.rc_fixed_pacing_rate_rec);
        else if (rack->r_ctl.cwnd_to_use < rack->rc_tp->snd_ssthresh)
                return (rack->r_ctl.rc_fixed_pacing_rate_ss);
        else
                return (rack->r_ctl.rc_fixed_pacing_rate_ca);
}

static void
rack_log_hybrid_bw(struct tcp_rack *rack, uint32_t seq, uint64_t cbw, uint64_t tim,
        uint64_t data, uint8_t mod, uint16_t aux,
        struct tcp_sendfile_track *cur, int line)
{
#ifdef TCP_REQUEST_TRK
        int do_log = 0;

        /*
         * The rate cap one is noisy and only should come out when normal BB logging
         * is enabled, the other logs (not RATE_CAP and NOT CAP_CALC) only come out
         * once per chunk and make up the BBpoint that can be turned on by the client.
         */
        if ((mod == HYBRID_LOG_RATE_CAP) || (mod == HYBRID_LOG_CAP_CALC)) {
                /*
                 * The very noisy two need to only come out when
                 * we have verbose logging on.
                 */
                if (rack_verbose_logging != 0)
                        do_log = tcp_bblogging_on(rack->rc_tp);
                else
                        do_log = 0;
        } else if (mod != HYBRID_LOG_BW_MEASURE) {
                /*
                 * All other less noisy logs here except the measure which
                 * also needs to come out on the point and the log.
                 */
                do_log = tcp_bblogging_on(rack->rc_tp);
        } else {
                do_log = tcp_bblogging_point_on(rack->rc_tp, TCP_BBPOINT_REQ_LEVEL_LOGGING);
        }

        if (do_log) {
                union tcp_log_stackspecific log;
                struct timeval tv;
                uint64_t lt_bw;

                /* Convert our ms to a microsecond */
                memset(&log, 0, sizeof(log));

                log.u_bbr.cwnd_gain = line;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.rttProp = tim;
                log.u_bbr.bw_inuse = cbw;
                log.u_bbr.delRate = rack_get_gp_est(rack);
                lt_bw = rack_get_lt_bw(rack);
                log.u_bbr.flex1 = seq;
                log.u_bbr.pacing_gain = aux;
                /* lt_bw = < flex3 | flex2 > */
                log.u_bbr.flex2 = (uint32_t)(lt_bw & 0x00000000ffffffff);
                log.u_bbr.flex3 = (uint32_t)((lt_bw >> 32) & 0x00000000ffffffff);
                /* Record the last obtained us rtt in inflight */
                if (cur == NULL) {
                        /* Make sure we are looking at the right log if an overide comes in */
                        cur = rack->r_ctl.rc_last_sft;
                }
                if (rack->r_ctl.rack_rs.rs_flags != RACK_RTT_EMPTY)
                        log.u_bbr.inflight = rack->r_ctl.rack_rs.rs_us_rtt;
                else {
                        /* Use the last known rtt i.e. the rack-rtt */
                        log.u_bbr.inflight = rack->rc_rack_rtt;
                }
                if (cur != NULL) {
                        uint64_t off;

                        log.u_bbr.cur_del_rate = cur->deadline;
                        if ((mod == HYBRID_LOG_RATE_CAP) || (mod == HYBRID_LOG_CAP_CALC)) {
                                /* start = < lost | pkt_epoch > */
                                log.u_bbr.pkt_epoch = (uint32_t)(cur->start & 0x00000000ffffffff);
                                log.u_bbr.lost = (uint32_t)((cur->start >> 32) & 0x00000000ffffffff);
                                log.u_bbr.flex6 = cur->start_seq;
                                log.u_bbr.pkts_out = cur->end_seq;
                        } else {
                                /* start = < lost | pkt_epoch > */
                                log.u_bbr.pkt_epoch = (uint32_t)(cur->start & 0x00000000ffffffff);
                                log.u_bbr.lost = (uint32_t)((cur->start >> 32) & 0x00000000ffffffff);
                                /* end = < pkts_out | flex6 > */
                                log.u_bbr.flex6 = (uint32_t)(cur->end & 0x00000000ffffffff);
                                log.u_bbr.pkts_out = (uint32_t)((cur->end >> 32) & 0x00000000ffffffff);
                        }
                        /* first_send = <lt_epoch | epoch> */
                        log.u_bbr.epoch = (uint32_t)(cur->first_send & 0x00000000ffffffff);
                        log.u_bbr.lt_epoch = (uint32_t)((cur->first_send >> 32) & 0x00000000ffffffff);
                        /* localtime = <delivered | applimited>*/
                        log.u_bbr.applimited = (uint32_t)(cur->localtime & 0x00000000ffffffff);
                        log.u_bbr.delivered = (uint32_t)((cur->localtime >> 32) & 0x00000000ffffffff);
#ifdef TCP_REQUEST_TRK
                        off = (uint64_t)(cur) - (uint64_t)(&rack->rc_tp->t_tcpreq_info[0]);
                        log.u_bbr.bbr_substate = (uint8_t)(off / sizeof(struct tcp_sendfile_track));
#endif
                        log.u_bbr.inhpts = 1;
                        log.u_bbr.flex4 = (uint32_t)(rack->rc_tp->t_sndbytes - cur->sent_at_fs);
                        log.u_bbr.flex5 = (uint32_t)(rack->rc_tp->t_snd_rxt_bytes - cur->rxt_at_fs);
                        log.u_bbr.flex7 = (uint16_t)cur->hybrid_flags;
                } else {
                        log.u_bbr.flex7 = 0xffff;
                        log.u_bbr.cur_del_rate = 0xffffffffffffffff;
                }
                /*
                 * Compose bbr_state to be a bit wise 0000ADHF
                 * where A is the always_pace flag
                 * where D is the dgp_on flag
                 * where H is the hybrid_mode on flag
                 * where F is the use_fixed_rate flag.
                 */
                log.u_bbr.bbr_state = rack->rc_always_pace;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->dgp_on;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->rc_hybrid_mode;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->use_fixed_rate;
                log.u_bbr.flex8 = mod;
                tcp_log_event(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_HYBRID_PACING_LOG, 0,
                    0, &log, false, NULL, __func__, __LINE__, &tv);

        }
#endif
}

#ifdef TCP_REQUEST_TRK
static void
rack_log_hybrid_sends(struct tcp_rack *rack, struct tcp_sendfile_track *cur, int line)
{
        if (tcp_bblogging_point_on(rack->rc_tp, TCP_BBPOINT_REQ_LEVEL_LOGGING)) {
                union tcp_log_stackspecific log;
                struct timeval tv;
                uint64_t off;

                /* Convert our ms to a microsecond */
                memset(&log, 0, sizeof(log));

                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.delRate = cur->sent_at_fs;

                if ((cur->flags & TCP_TRK_TRACK_FLG_LSND) == 0) {
                        /*
                         * We did not get a new Rules Applied to set so
                         * no overlapping send occured, this means the
                         * current byte counts are correct.
                         */
                        log.u_bbr.cur_del_rate = rack->rc_tp->t_sndbytes;
                        log.u_bbr.rttProp = rack->rc_tp->t_snd_rxt_bytes;
                } else {
                        /*
                         * Overlapping send case, we switched to a new
                         * send and did a rules applied.
                         */
                        log.u_bbr.cur_del_rate = cur->sent_at_ls;
                        log.u_bbr.rttProp = cur->rxt_at_ls;
                }
                log.u_bbr.bw_inuse = cur->rxt_at_fs;
                log.u_bbr.cwnd_gain = line;
                off = (uint64_t)(cur) - (uint64_t)(&rack->rc_tp->t_tcpreq_info[0]);
                log.u_bbr.bbr_substate = (uint8_t)(off / sizeof(struct tcp_sendfile_track));
                /* start = < flex1 | flex2 > */
                log.u_bbr.flex2 = (uint32_t)(cur->start & 0x00000000ffffffff);
                log.u_bbr.flex1 = (uint32_t)((cur->start >> 32) & 0x00000000ffffffff);
                /* end = < flex3 | flex4 > */
                log.u_bbr.flex4 = (uint32_t)(cur->end & 0x00000000ffffffff);
                log.u_bbr.flex3 = (uint32_t)((cur->end >> 32) & 0x00000000ffffffff);

                /* localtime = <delivered | applimited>*/
                log.u_bbr.applimited = (uint32_t)(cur->localtime & 0x00000000ffffffff);
                log.u_bbr.delivered = (uint32_t)((cur->localtime >> 32) & 0x00000000ffffffff);
                /* client timestamp = <lt_epoch | epoch>*/
                log.u_bbr.epoch = (uint32_t)(cur->timestamp & 0x00000000ffffffff);
                log.u_bbr.lt_epoch = (uint32_t)((cur->timestamp >> 32) & 0x00000000ffffffff);
                /* now set all the flags in */
                log.u_bbr.pkts_out = cur->hybrid_flags;
                log.u_bbr.lost = cur->playout_ms;
                log.u_bbr.flex6 = cur->flags;
                /*
                 * Last send time  = <flex5 | pkt_epoch>  note we do not distinguish cases
                 * where a false retransmit occurred so first_send  <-> lastsend may
                 * include longer time then it actually took if we have a false rxt.
                 */
                log.u_bbr.pkt_epoch = (uint32_t)(rack->r_ctl.last_tmit_time_acked & 0x00000000ffffffff);
                log.u_bbr.flex5 = (uint32_t)((rack->r_ctl.last_tmit_time_acked >> 32) & 0x00000000ffffffff);
                /*
                 * Compose bbr_state to be a bit wise 0000ADHF
                 * where A is the always_pace flag
                 * where D is the dgp_on flag
                 * where H is the hybrid_mode on flag
                 * where F is the use_fixed_rate flag.
                 */
                log.u_bbr.bbr_state = rack->rc_always_pace;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->dgp_on;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->rc_hybrid_mode;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->use_fixed_rate;

                log.u_bbr.flex8 = HYBRID_LOG_SENT_LOST;
                tcp_log_event(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_HYBRID_PACING_LOG, 0,
                    0, &log, false, NULL, __func__, __LINE__, &tv);
        }
}
#endif

static inline uint64_t
rack_compensate_for_linerate(struct tcp_rack *rack, uint64_t bw)
{
        uint64_t ret_bw, ether;
        uint64_t u_segsiz;

        ether = rack->rc_tp->t_maxseg + sizeof(struct tcphdr);
        if (rack->r_is_v6){
#ifdef INET6
                ether += sizeof(struct ip6_hdr);
#endif
                ether += 14;    /* eheader size 6+6+2 */
        } else {
#ifdef INET
                ether += sizeof(struct ip);
#endif
                ether += 14;    /* eheader size 6+6+2 */
        }
        u_segsiz = (uint64_t)min(ctf_fixed_maxseg(rack->rc_tp), rack->r_ctl.rc_pace_min_segs);
        ret_bw = bw;
        ret_bw *= ether;
        ret_bw /= u_segsiz;
        return (ret_bw);
}

static void
rack_rate_cap_bw(struct tcp_rack *rack, uint64_t *bw, int *capped)
{
#ifdef TCP_REQUEST_TRK
        struct timeval tv;
        uint64_t timenow, timeleft, lenleft, lengone, calcbw;
#endif

        if (rack->r_ctl.bw_rate_cap == 0)
                return;
#ifdef TCP_REQUEST_TRK
        if (rack->rc_catch_up && rack->rc_hybrid_mode &&
            (rack->r_ctl.rc_last_sft != NULL)) {
                /*
                 * We have a dynamic cap. The original target
                 * is in bw_rate_cap, but we need to look at
                 * how long it is until we hit the deadline.
                 */
                struct tcp_sendfile_track *ent;

                ent = rack->r_ctl.rc_last_sft;
                microuptime(&tv);
                timenow = tcp_tv_to_lusec(&tv);
                if (timenow >= ent->deadline) {
                        /* No time left we do DGP only */
                        rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                           0, 0, 0, HYBRID_LOG_OUTOFTIME, 0, ent, __LINE__);
                        rack->r_ctl.bw_rate_cap = 0;
                        return;
                }
                /* We have the time */
                timeleft = rack->r_ctl.rc_last_sft->deadline - timenow;
                if (timeleft < HPTS_MSEC_IN_SEC) {
                        /* If there is less than a ms left just use DGPs rate */
                        rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                           0, timeleft, 0, HYBRID_LOG_OUTOFTIME, 0, ent, __LINE__);
                        rack->r_ctl.bw_rate_cap = 0;
                        return;
                }
                /*
                 * Now lets find the amount of data left to send.
                 *
                 * Now ideally we want to use the end_seq to figure out how much more
                 * but it might not be possible (only if we have the TRACK_FG_COMP on the entry..
                 */
                if (ent->flags & TCP_TRK_TRACK_FLG_COMP) {
                        if (SEQ_GT(ent->end_seq, rack->rc_tp->snd_una))
                                lenleft = ent->end_seq - rack->rc_tp->snd_una;
                        else {
                                /* TSNH, we should catch it at the send */
                                rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                                   0, timeleft, 0, HYBRID_LOG_CAPERROR, 0, ent, __LINE__);
                                rack->r_ctl.bw_rate_cap = 0;
                                return;
                        }
                } else {
                        /*
                         * The hard way, figure out how much is gone and then
                         * take that away from the total the client asked for
                         * (thats off by tls overhead if this is tls).
                         */
                        if (SEQ_GT(rack->rc_tp->snd_una, ent->start_seq))
                                lengone = rack->rc_tp->snd_una - ent->start_seq;
                        else
                                lengone = 0;
                        if (lengone < (ent->end - ent->start))
                                lenleft = (ent->end - ent->start) - lengone;
                        else {
                                /* TSNH, we should catch it at the send */
                                rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                                   0, timeleft, lengone, HYBRID_LOG_CAPERROR, 0, ent, __LINE__);
                                rack->r_ctl.bw_rate_cap = 0;
                                return;
                        }
                }
                if (lenleft == 0) {
                        /* We have it all sent */
                        rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                           0, timeleft, lenleft, HYBRID_LOG_ALLSENT, 0, ent, __LINE__);
                        if (rack->r_ctl.bw_rate_cap)
                                goto normal_ratecap;
                        else
                                return;
                }
                calcbw = lenleft * HPTS_USEC_IN_SEC;
                calcbw /= timeleft;
                /* Now we must compensate for IP/TCP overhead */
                calcbw = rack_compensate_for_linerate(rack, calcbw);
                /* Update the bit rate cap */
                rack->r_ctl.bw_rate_cap = calcbw;
                if ((rack->r_ctl.rc_last_sft->hybrid_flags & TCP_HYBRID_PACING_S_MSS) &&
                    (rack_hybrid_allow_set_maxseg == 1) &&
                    ((rack->r_ctl.rc_last_sft->hybrid_flags & TCP_HYBRID_PACING_SETMSS) == 0)) {
                        /* Lets set in a smaller mss possibly here to match our rate-cap */
                        uint32_t orig_max;

                        orig_max = rack->r_ctl.rc_pace_max_segs;
                        rack->r_ctl.rc_last_sft->hybrid_flags |= TCP_HYBRID_PACING_SETMSS;
                        rack->r_ctl.rc_pace_max_segs = rack_get_pacing_len(rack, calcbw, ctf_fixed_maxseg(rack->rc_tp));
                        rack_log_type_pacing_sizes(rack->rc_tp, rack, rack->r_ctl.client_suggested_maxseg, orig_max, __LINE__, 5);
                }
                rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                   calcbw, timeleft, lenleft, HYBRID_LOG_CAP_CALC, 0, ent, __LINE__);
                if ((calcbw > 0) && (*bw > calcbw)) {
                        rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                           *bw, ent->deadline, lenleft, HYBRID_LOG_RATE_CAP, 0, ent, __LINE__);
                        *capped = 1;
                        *bw = calcbw;
                }
                return;
        }
normal_ratecap:
#endif
        if ((rack->r_ctl.bw_rate_cap > 0) && (*bw > rack->r_ctl.bw_rate_cap)) {
#ifdef TCP_REQUEST_TRK
                if (rack->rc_hybrid_mode &&
                    rack->rc_catch_up &&
                    (rack->r_ctl.rc_last_sft != NULL) &&
                    (rack->r_ctl.rc_last_sft->hybrid_flags & TCP_HYBRID_PACING_S_MSS) &&
                    (rack_hybrid_allow_set_maxseg == 1) &&
                    ((rack->r_ctl.rc_last_sft->hybrid_flags & TCP_HYBRID_PACING_SETMSS) == 0)) {
                        /* Lets set in a smaller mss possibly here to match our rate-cap */
                        uint32_t orig_max;

                        orig_max = rack->r_ctl.rc_pace_max_segs;
                        rack->r_ctl.rc_last_sft->hybrid_flags |= TCP_HYBRID_PACING_SETMSS;
                        rack->r_ctl.rc_pace_max_segs = rack_get_pacing_len(rack, rack->r_ctl.bw_rate_cap, ctf_fixed_maxseg(rack->rc_tp));
                        rack_log_type_pacing_sizes(rack->rc_tp, rack, rack->r_ctl.client_suggested_maxseg, orig_max, __LINE__, 5);
                }
#endif
                *capped = 1;
                *bw = rack->r_ctl.bw_rate_cap;
                rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                   *bw, 0, 0,
                                   HYBRID_LOG_RATE_CAP, 1, NULL, __LINE__);
        }
}

static uint64_t
rack_get_gp_est(struct tcp_rack *rack)
{
        uint64_t bw, lt_bw, ret_bw;

        if (rack->rc_gp_filled == 0) {
                /*
                 * We have yet no b/w measurement,
                 * if we have a user set initial bw
                 * return it. If we don't have that and
                 * we have an srtt, use the tcp IW (10) to
                 * calculate a fictional b/w over the SRTT
                 * which is more or less a guess. Note
                 * we don't use our IW from rack on purpose
                 * so if we have like IW=30, we are not
                 * calculating a "huge" b/w.
                 */
                uint64_t srtt;

                if (rack->dis_lt_bw == 1)
                        lt_bw = 0;
                else
                        lt_bw = rack_get_lt_bw(rack);
                if (lt_bw) {
                        /*
                         * No goodput bw but a long-term b/w does exist
                         * lets use that.
                         */
                        ret_bw = lt_bw;
                        goto compensate;
                }
                if (rack->r_ctl.init_rate)
                        return (rack->r_ctl.init_rate);

                /* Ok lets come up with the IW guess, if we have a srtt */
                if (rack->rc_tp->t_srtt == 0) {
                        /*
                         * Go with old pacing method
                         * i.e. burst mitigation only.
                         */
                        return (0);
                }
                /* Ok lets get the initial TCP win (not racks) */
                bw = tcp_compute_initwnd(tcp_maxseg(rack->rc_tp));
                srtt = (uint64_t)rack->rc_tp->t_srtt;
                bw *= (uint64_t)USECS_IN_SECOND;
                bw /= srtt;
                ret_bw = bw;
                goto compensate;

        }
        if (rack->r_ctl.num_measurements >= RACK_REQ_AVG) {
                /* Averaging is done, we can return the value */
                bw = rack->r_ctl.gp_bw;
        } else {
                /* Still doing initial average must calculate */
                bw = rack->r_ctl.gp_bw / max(rack->r_ctl.num_measurements, 1);
        }
        if (rack->dis_lt_bw) {
                /* We are not using lt-bw */
                ret_bw = bw;
                goto compensate;
        }
        lt_bw = rack_get_lt_bw(rack);
        if (lt_bw == 0) {
                /* If we don't have one then equate it to the gp_bw */
                lt_bw = rack->r_ctl.gp_bw;
        }
        if (rack->use_lesser_lt_bw) {
                if (lt_bw < bw)
                        ret_bw = lt_bw;
                else
                        ret_bw = bw;
        } else {
                if (lt_bw > bw)
                        ret_bw = lt_bw;
                else
                        ret_bw = bw;
        }
        /*
         * Now lets compensate based on the TCP/IP overhead. Our
         * Goodput estimate does not include this so we must pace out
         * a bit faster since our pacing calculations do. The pacing
         * calculations use the base ETHERNET_SEGMENT_SIZE and the segsiz
         * we are using to do this, so we do that here in the opposite
         * direction as well. This means that if we are tunneled and the
         * segsiz is say 1200 bytes we will get quite a boost, but its
         * compensated for in the pacing time the opposite way.
         */
compensate:
        ret_bw = rack_compensate_for_linerate(rack, ret_bw);
        return(ret_bw);
}


static uint64_t
rack_get_bw(struct tcp_rack *rack)
{
        uint64_t bw;

        if (rack->use_fixed_rate) {
                /* Return the fixed pacing rate */
                return (rack_get_fixed_pacing_bw(rack));
        }
        bw = rack_get_gp_est(rack);
        return (bw);
}

static uint16_t
rack_get_output_gain(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
        if (rack->use_fixed_rate) {
                return (100);
        } else if (rack->in_probe_rtt && (rsm == NULL))
                return (rack->r_ctl.rack_per_of_gp_probertt);
        else if ((IN_FASTRECOVERY(rack->rc_tp->t_flags) &&
                  rack->r_ctl.rack_per_of_gp_rec)) {
                if (rsm) {
                        /* a retransmission always use the recovery rate */
                        return (rack->r_ctl.rack_per_of_gp_rec);
                } else if (rack->rack_rec_nonrxt_use_cr) {
                        /* Directed to use the configured rate */
                        goto configured_rate;
                } else if (rack->rack_no_prr &&
                           (rack->r_ctl.rack_per_of_gp_rec > 100)) {
                        /* No PRR, lets just use the b/w estimate only */
                        return (100);
                } else {
                        /*
                         * Here we may have a non-retransmit but we
                         * have no overrides, so just use the recovery
                         * rate (prr is in effect).
                         */
                        return (rack->r_ctl.rack_per_of_gp_rec);
                }
        }
configured_rate:
        /* For the configured rate we look at our cwnd vs the ssthresh */
        if (rack->r_ctl.cwnd_to_use < rack->rc_tp->snd_ssthresh)
                return (rack->r_ctl.rack_per_of_gp_ss);
        else
                return (rack->r_ctl.rack_per_of_gp_ca);
}

static void
rack_log_dsack_event(struct tcp_rack *rack, uint8_t mod, uint32_t flex4, uint32_t flex5, uint32_t flex6)
{
        /*
         * Types of logs (mod value)
         * 1 = dsack_persists reduced by 1 via T-O or fast recovery exit.
         * 2 = a dsack round begins, persist is reset to 16.
         * 3 = a dsack round ends
         * 4 = Dsack option increases rack rtt flex5 is the srtt input, flex6 is thresh
         * 5 = Socket option set changing the control flags rc_rack_tmr_std_based, rc_rack_use_dsack
         * 6 = Final rack rtt, flex4 is srtt and flex6 is final limited thresh.
         */
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rack->rc_rack_tmr_std_based;
                log.u_bbr.flex1 <<= 1;
                log.u_bbr.flex1 |= rack->rc_rack_use_dsack;
                log.u_bbr.flex1 <<= 1;
                log.u_bbr.flex1 |= rack->rc_dsack_round_seen;
                log.u_bbr.flex2 = rack->r_ctl.dsack_round_end;
                log.u_bbr.flex3 = rack->r_ctl.num_dsack;
                log.u_bbr.flex4 = flex4;
                log.u_bbr.flex5 = flex5;
                log.u_bbr.flex6 = flex6;
                log.u_bbr.flex7 = rack->r_ctl.dsack_persist;
                log.u_bbr.flex8 = mod;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.epoch = rack->r_ctl.current_round;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    RACK_DSACK_HANDLING, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_hdwr_pacing(struct tcp_rack *rack,
                     uint64_t rate, uint64_t hw_rate, int line,
                     int error, uint16_t mod)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;
                const struct ifnet *ifp;
                uint64_t ifp64;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = ((hw_rate >> 32) & 0x00000000ffffffff);
                log.u_bbr.flex2 = (hw_rate & 0x00000000ffffffff);
                if (rack->r_ctl.crte) {
                        ifp = rack->r_ctl.crte->ptbl->rs_ifp;
                } else if (rack->rc_inp->inp_route.ro_nh &&
                           rack->rc_inp->inp_route.ro_nh->nh_ifp) {
                        ifp = rack->rc_inp->inp_route.ro_nh->nh_ifp;
                } else
                        ifp = NULL;
                if (ifp) {
                        ifp64 = (uintptr_t)ifp;
                        log.u_bbr.flex3 = ((ifp64  >> 32) & 0x00000000ffffffff);
                        log.u_bbr.flex4 = (ifp64 & 0x00000000ffffffff);
                }
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.bw_inuse = rate;
                log.u_bbr.flex5 = line;
                log.u_bbr.flex6 = error;
                log.u_bbr.flex7 = mod;
                log.u_bbr.applimited = rack->r_ctl.rc_pace_max_segs;
                log.u_bbr.flex8 = rack->use_fixed_rate;
                log.u_bbr.flex8 <<= 1;
                log.u_bbr.flex8 |= rack->rack_hdrw_pacing;
                log.u_bbr.pkts_out = rack->rc_tp->t_maxseg;
                log.u_bbr.delRate = rack->r_ctl.crte_prev_rate;
                if (rack->r_ctl.crte)
                        log.u_bbr.cur_del_rate = rack->r_ctl.crte->rate;
                else
                        log.u_bbr.cur_del_rate = 0;
                log.u_bbr.rttProp = rack->r_ctl.last_hw_bw_req;
                log.u_bbr.epoch = rack->r_ctl.current_round;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_HDWR_PACE, 0,
                    0, &log, false, &tv);
        }
}

static uint64_t
rack_get_output_bw(struct tcp_rack *rack, uint64_t bw, struct rack_sendmap *rsm, int *capped)
{
        /*
         * We allow rack_per_of_gp_xx to dictate our bw rate we want.
         */
        uint64_t bw_est, high_rate;
        uint64_t gain;

        gain = (uint64_t)rack_get_output_gain(rack, rsm);
        bw_est = bw * gain;
        bw_est /= (uint64_t)100;
        /* Never fall below the minimum (def 64kbps) */
        if (bw_est < RACK_MIN_BW)
                bw_est = RACK_MIN_BW;
        if (rack->r_rack_hw_rate_caps) {
                /* Rate caps are in place */
                if (rack->r_ctl.crte != NULL) {
                        /* We have a hdwr rate already */
                        high_rate = tcp_hw_highest_rate(rack->r_ctl.crte);
                        if (bw_est >= high_rate) {
                                /* We are capping bw at the highest rate table entry */
                                if (rack_hw_rate_cap_per &&
                                    (((high_rate * (100 + rack_hw_rate_cap_per)) / 100) < bw_est)) {
                                        rack->r_rack_hw_rate_caps = 0;
                                        goto done;
                                }
                                rack_log_hdwr_pacing(rack,
                                                     bw_est, high_rate, __LINE__,
                                                     0, 3);
                                bw_est = high_rate;
                                if (capped)
                                        *capped = 1;
                        }
                } else if ((rack->rack_hdrw_pacing == 0) &&
                           (rack->rack_hdw_pace_ena) &&
                           (rack->rack_attempt_hdwr_pace == 0) &&
                           (rack->rc_inp->inp_route.ro_nh != NULL) &&
                           (rack->rc_inp->inp_route.ro_nh->nh_ifp != NULL)) {
                        /*
                         * Special case, we have not yet attempted hardware
                         * pacing, and yet we may, when we do, find out if we are
                         * above the highest rate. We need to know the maxbw for the interface
                         * in question (if it supports ratelimiting). We get back
                         * a 0, if the interface is not found in the RL lists.
                         */
                        high_rate = tcp_hw_highest_rate_ifp(rack->rc_inp->inp_route.ro_nh->nh_ifp, rack->rc_inp);
                        if (high_rate) {
                                /* Yep, we have a rate is it above this rate? */
                                if (bw_est > high_rate) {
                                        bw_est = high_rate;
                                        if (capped)
                                                *capped = 1;
                                }
                        }
                }
        }
done:
        return (bw_est);
}

static void
rack_log_retran_reason(struct tcp_rack *rack, struct rack_sendmap *rsm, uint32_t tsused, uint32_t thresh, int mod)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                if ((mod != 1) && (rack_verbose_logging == 0))  {
                        /*
                         * We get 3 values currently for mod
                         * 1 - We are retransmitting and this tells the reason.
                         * 2 - We are clearing a dup-ack count.
                         * 3 - We are incrementing a dup-ack count.
                         *
                         * The clear/increment are only logged
                         * if you have BBverbose on.
                         */
                        return;
                }
                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = tsused;
                log.u_bbr.flex2 = thresh;
                log.u_bbr.flex3 = rsm->r_flags;
                log.u_bbr.flex4 = rsm->r_dupack;
                log.u_bbr.flex5 = rsm->r_start;
                log.u_bbr.flex6 = rsm->r_end;
                log.u_bbr.flex8 = mod;
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.epoch = rack->r_ctl.current_round;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_SETTINGS_CHG, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_to_start(struct tcp_rack *rack, uint32_t cts, uint32_t to, int32_t pacing_delay, uint8_t which)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rack->rc_tp->t_srtt;
                log.u_bbr.flex2 = to;
                log.u_bbr.flex3 = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.flex4 = pacing_delay;
                log.u_bbr.flex5 = rack->rc_tp->t_hpts_slot;
                log.u_bbr.flex6 = rack->rc_tp->t_rxtcur;
                log.u_bbr.flex7 = rack->rc_in_persist;
                log.u_bbr.flex8 = which;
                if (rack->rack_no_prr)
                        log.u_bbr.pkts_out = 0;
                else
                        log.u_bbr.pkts_out = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.cwnd_gain = rack->rack_deferred_inited;
                log.u_bbr.pkt_epoch = rack->rc_has_collapsed;
                log.u_bbr.lt_epoch = rack->rc_tp->t_rxtshift;
                log.u_bbr.lost = rack_rto_min;
                log.u_bbr.epoch = rack->r_ctl.roundends;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                log.u_bbr.applimited = rack->rc_tp->t_flags2;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_TIMERSTAR, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_to_event(struct tcp_rack *rack, int32_t to_num, struct rack_sendmap *rsm)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex8 = to_num;
                log.u_bbr.flex1 = rack->r_ctl.rc_rack_min_rtt;
                log.u_bbr.flex2 = rack->rc_rack_rtt;
                if (rsm == NULL)
                        log.u_bbr.flex3 = 0;
                else
                        log.u_bbr.flex3 = rsm->r_end - rsm->r_start;
                if (rack->rack_no_prr)
                        log.u_bbr.flex5 = 0;
                else
                        log.u_bbr.flex5 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_RTO, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_map_chg(struct tcpcb *tp, struct tcp_rack *rack,
                 struct rack_sendmap *prev,
                 struct rack_sendmap *rsm,
                 struct rack_sendmap *next,
                 int flag, uint32_t th_ack, int line)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex8 = flag;
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.cur_del_rate = (uintptr_t)prev;
                log.u_bbr.delRate = (uintptr_t)rsm;
                log.u_bbr.rttProp = (uintptr_t)next;
                if (rsm)
                        log.u_bbr.flex1 = rsm->r_flags;
                log.u_bbr.flex7 = 0;
                if (prev) {
                        log.u_bbr.flex1 = prev->r_start;
                        log.u_bbr.flex2 = prev->r_end;
                        log.u_bbr.flex7 |= 0x4;
                }
                if (rsm) {
                        log.u_bbr.flex3 = rsm->r_start;
                        log.u_bbr.flex4 = rsm->r_end;
                        log.u_bbr.flex7 |= 0x2;
                }
                if (next) {
                        log.u_bbr.flex5 = next->r_start;
                        log.u_bbr.flex6 = next->r_end;
                        log.u_bbr.flex7 |= 0x1;
                }
                log.u_bbr.applimited = line;
                log.u_bbr.pkts_out = th_ack;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                if (rack->rack_no_prr)
                        log.u_bbr.lost = 0;
                else
                        log.u_bbr.lost = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_LOG_MAPCHG, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_rtt_upd(struct tcpcb *tp, struct tcp_rack *rack, uint32_t t, uint32_t len,
                 struct rack_sendmap *rsm, int conf)
{
        if (tcp_bblogging_on(tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;
                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = t;
                log.u_bbr.flex2 = len;
                log.u_bbr.flex3 = rack->r_ctl.rc_rack_min_rtt;
                log.u_bbr.flex4 = rack->r_ctl.rack_rs.rs_rtt_lowest;
                log.u_bbr.flex5 = rack->r_ctl.rack_rs.rs_rtt_highest;
                log.u_bbr.flex6 = rack->r_ctl.rack_rs.rs_us_rtrcnt;
                log.u_bbr.flex7 = conf;
                log.u_bbr.rttProp = (uint64_t)rack->r_ctl.rack_rs.rs_rtt_tot;
                log.u_bbr.flex8 = rack->r_ctl.rc_rate_sample_method;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.delivered = rack->r_ctl.rack_rs.rs_us_rtrcnt;
                log.u_bbr.pkts_out = rack->r_ctl.rack_rs.rs_flags;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                if (rsm) {
                        log.u_bbr.pkt_epoch = rsm->r_start;
                        log.u_bbr.lost = rsm->r_end;
                        log.u_bbr.cwnd_gain = rsm->r_rtr_cnt;
                        /* We loose any upper of the 24 bits */
                        log.u_bbr.pacing_gain = (uint16_t)rsm->r_flags;
                } else {
                        /* Its a SYN */
                        log.u_bbr.pkt_epoch = rack->rc_tp->iss;
                        log.u_bbr.lost = 0;
                        log.u_bbr.cwnd_gain = 0;
                        log.u_bbr.pacing_gain = 0;
                }
                /* Write out general bits of interest rrs here */
                log.u_bbr.use_lt_bw = rack->rc_highly_buffered;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->forced_ack;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->rc_gp_dyn_mul;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->in_probe_rtt;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->measure_saw_probe_rtt;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->app_limited_needs_set;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->rc_gp_filled;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->rc_dragged_bottom;
                log.u_bbr.applimited = rack->r_ctl.rc_target_probertt_flight;
                log.u_bbr.epoch = rack->r_ctl.rc_time_probertt_starts;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_time_probertt_entered;
                log.u_bbr.cur_del_rate = rack->r_ctl.rc_lower_rtt_us_cts;
                log.u_bbr.delRate = rack->r_ctl.rc_gp_srtt;
                log.u_bbr.bw_inuse = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
                log.u_bbr.bw_inuse <<= 32;
                if (rsm)
                        log.u_bbr.bw_inuse |= ((uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)]);
                TCP_LOG_EVENTP(tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_BBRRTT, 0,
                    0, &log, false, &tv);


        }
}

static void
rack_log_rtt_sample(struct tcp_rack *rack, uint32_t rtt)
{
        /*
         * Log the rtt sample we are
         * applying to the srtt algorithm in
         * useconds.
         */
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                /* Convert our ms to a microsecond */
                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rtt;
                log.u_bbr.flex6 = rack->rc_tp->t_rxtcur;
                log.u_bbr.flex7 = 1;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                /*
                 * We capture in delRate the upper 32 bits as
                 * the confidence level we had declared, and the
                 * lower 32 bits as the actual RTT using the arrival
                 * timestamp.
                 */
                log.u_bbr.delRate = rack->r_ctl.rack_rs.confidence;
                log.u_bbr.delRate <<= 32;
                log.u_bbr.delRate |= rack->r_ctl.rack_rs.rs_us_rtt;
                /* Lets capture all the things that make up t_rtxcur */
                log.u_bbr.applimited = rack_rto_min;
                log.u_bbr.epoch = rack_rto_max;
                log.u_bbr.lt_epoch = rack->r_ctl.timer_slop;
                log.u_bbr.lost = rack_rto_min;
                log.u_bbr.pkt_epoch = TICKS_2_USEC(tcp_rexmit_slop);
                log.u_bbr.rttProp = RACK_REXMTVAL(rack->rc_tp);
                log.u_bbr.bw_inuse = rack->r_ctl.act_rcv_time.tv_sec;
                log.u_bbr.bw_inuse *= HPTS_USEC_IN_SEC;
                log.u_bbr.bw_inuse += rack->r_ctl.act_rcv_time.tv_usec;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_LOG_RTT, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_rtt_sample_calc(struct tcp_rack *rack, uint32_t rtt, uint32_t send_time, uint32_t ack_time, int where)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                /* Convert our ms to a microsecond */
                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rtt;
                log.u_bbr.flex2 = send_time;
                log.u_bbr.flex3 = ack_time;
                log.u_bbr.flex4 = where;
                log.u_bbr.flex7 = 2;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_LOG_RTT, 0,
                    0, &log, false, &tv);
        }
}


static void
rack_log_rtt_sendmap(struct tcp_rack *rack, uint32_t idx, uint64_t tsv, uint32_t tsecho)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                /* Convert our ms to a microsecond */
                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = idx;
                log.u_bbr.flex2 = rack_ts_to_msec(tsv);
                log.u_bbr.flex3 = tsecho;
                log.u_bbr.flex7 = 3;
                log.u_bbr.rttProp = tsv;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_LOG_RTT, 0,
                    0, &log, false, &tv);
        }
}


static inline void
rack_log_progress_event(struct tcp_rack *rack, struct tcpcb *tp, uint32_t tick,  int event, int line)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = line;
                log.u_bbr.flex2 = tick;
                log.u_bbr.flex3 = tp->t_maxunacktime;
                log.u_bbr.flex4 = tp->t_acktime;
                log.u_bbr.flex8 = event;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_PROGRESS, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_type_bbrsnd(struct tcp_rack *rack, uint32_t len, uint32_t pacing_delay, uint32_t cts, struct timeval *tv, int line)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = pacing_delay;
                if (rack->rack_no_prr)
                        log.u_bbr.flex2 = 0;
                else
                        log.u_bbr.flex2 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex4 = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.flex6 = line;
                log.u_bbr.flex7 = (0x0000ffff & rack->r_ctl.rc_hpts_flags);
                log.u_bbr.flex8 = rack->rc_in_persist;
                log.u_bbr.timeStamp = cts;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_BBRSND, 0,
                    0, &log, false, tv);
        }
}

static void
rack_log_doseg_done(struct tcp_rack *rack, uint32_t cts, int32_t nxt_pkt, int32_t did_out, int way_out, int nsegs)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = did_out;
                log.u_bbr.flex2 = nxt_pkt;
                log.u_bbr.flex3 = way_out;
                log.u_bbr.flex4 = rack->r_ctl.rc_hpts_flags;
                if (rack->rack_no_prr)
                        log.u_bbr.flex5 = 0;
                else
                        log.u_bbr.flex5 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex6 = nsegs;
                log.u_bbr.applimited = rack->r_ctl.rc_pace_min_segs;
                log.u_bbr.flex7 = rack->rc_ack_can_sendout_data;        /* Do we have ack-can-send set */
                log.u_bbr.flex7 <<= 1;
                log.u_bbr.flex7 |= rack->r_fast_output; /* is fast output primed */
                log.u_bbr.flex7 <<= 1;
                log.u_bbr.flex7 |= rack->r_wanted_output;       /* Do we want output */
                log.u_bbr.flex8 = rack->rc_in_persist;
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.use_lt_bw = rack->r_ent_rec_ns;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->r_might_revert;
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                log.u_bbr.epoch = rack->rc_inp->inp_socket->so_snd.sb_hiwat;
                log.u_bbr.lt_epoch = rack->rc_inp->inp_socket->so_rcv.sb_hiwat;
                log.u_bbr.lost = rack->rc_tp->t_srtt;
                log.u_bbr.pkt_epoch = rack->rc_tp->rfbuf_cnt;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_DOSEG_DONE, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_type_pacing_sizes(struct tcpcb *tp, struct tcp_rack *rack, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint8_t frm)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rack->r_ctl.rc_pace_min_segs;
                log.u_bbr.flex3 = rack->r_ctl.rc_pace_max_segs;
                log.u_bbr.flex4 = arg1;
                log.u_bbr.flex5 = arg2;
                log.u_bbr.flex7 = rack->r_ctl.rc_user_set_min_segs;
                log.u_bbr.flex6 = arg3;
                log.u_bbr.flex8 = frm;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.applimited = rack->r_ctl.rc_sacked;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                TCP_LOG_EVENTP(tp, NULL, &tptosocket(tp)->so_rcv,
                    &tptosocket(tp)->so_snd,
                    TCP_HDWR_PACE_SIZE, 0, 0, &log, false, &tv);
        }
}

static void
rack_log_type_just_return(struct tcp_rack *rack, uint32_t cts, uint32_t tlen, uint32_t pacing_delay,
                          uint8_t hpts_calling, int reason, uint32_t cwnd_to_use)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = pacing_delay;
                log.u_bbr.flex2 = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.flex4 = reason;
                if (rack->rack_no_prr)
                        log.u_bbr.flex5 = 0;
                else
                        log.u_bbr.flex5 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex7 = hpts_calling;
                log.u_bbr.flex8 = rack->rc_in_persist;
                log.u_bbr.lt_epoch = cwnd_to_use;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.cwnd_gain = rack->rc_has_collapsed;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_JUSTRET, 0,
                    tlen, &log, false, &tv);
        }
}

static void
rack_log_to_cancel(struct tcp_rack *rack, int32_t hpts_removed, int line, uint32_t us_cts,
                   struct timeval *tv, uint32_t flags_on_entry)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = line;
                log.u_bbr.flex2 = rack->r_ctl.rc_last_output_to;
                log.u_bbr.flex3 = flags_on_entry;
                log.u_bbr.flex4 = us_cts;
                if (rack->rack_no_prr)
                        log.u_bbr.flex5 = 0;
                else
                        log.u_bbr.flex5 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex6 = rack->rc_tp->t_rxtcur;
                log.u_bbr.flex7 = hpts_removed;
                log.u_bbr.flex8 = 1;
                log.u_bbr.applimited = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.timeStamp = us_cts;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.bw_inuse = rack->r_ctl.current_round;
                log.u_bbr.bw_inuse <<= 32;
                log.u_bbr.bw_inuse |= rack->r_ctl.rc_considered_lost;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_TIMERCANC, 0,
                    0, &log, false, tv);
        }
}

static void
rack_log_alt_to_to_cancel(struct tcp_rack *rack,
                          uint32_t flex1, uint32_t flex2,
                          uint32_t flex3, uint32_t flex4,
                          uint32_t flex5, uint32_t flex6,
                          uint16_t flex7, uint8_t mod)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                if (mod == 1) {
                        /* No you can't use 1, its for the real to cancel */
                        return;
                }
                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex1 = flex1;
                log.u_bbr.flex2 = flex2;
                log.u_bbr.flex3 = flex3;
                log.u_bbr.flex4 = flex4;
                log.u_bbr.flex5 = flex5;
                log.u_bbr.flex6 = flex6;
                log.u_bbr.flex7 = flex7;
                log.u_bbr.flex8 = mod;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_TIMERCANC, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_to_processing(struct tcp_rack *rack, uint32_t cts, int32_t ret, int32_t timers)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = timers;
                log.u_bbr.flex2 = ret;
                log.u_bbr.flex3 = rack->r_ctl.rc_timer_exp;
                log.u_bbr.flex4 = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.flex5 = cts;
                if (rack->rack_no_prr)
                        log.u_bbr.flex6 = 0;
                else
                        log.u_bbr.flex6 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.pkts_out = rack->r_ctl.rc_out_at_rto;
                log.u_bbr.delivered = rack->r_ctl.rc_snd_max_at_rto;
                log.u_bbr.pacing_gain = rack->r_must_retran;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_TO_PROCESS, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_log_to_prr(struct tcp_rack *rack, int frm, int orig_cwnd, int line)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rack->r_ctl.rc_prr_out;
                log.u_bbr.flex2 = rack->r_ctl.rc_prr_recovery_fs;
                if (rack->rack_no_prr)
                        log.u_bbr.flex3 = 0;
                else
                        log.u_bbr.flex3 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex4 = rack->r_ctl.rc_prr_delivered;
                log.u_bbr.flex5 = rack->r_ctl.rc_sacked;
                log.u_bbr.flex6 = rack->r_ctl.rc_holes_rxt;
                log.u_bbr.flex7 = line;
                log.u_bbr.flex8 = frm;
                log.u_bbr.pkts_out = orig_cwnd;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.use_lt_bw = rack->r_ent_rec_ns;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->r_might_revert;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_BBRUPD, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_counter_destroy(void)
{
        counter_u64_free(rack_total_bytes);
        counter_u64_free(rack_fto_send);
        counter_u64_free(rack_fto_rsm_send);
        counter_u64_free(rack_nfto_resend);
        counter_u64_free(rack_hw_pace_init_fail);
        counter_u64_free(rack_hw_pace_lost);
        counter_u64_free(rack_non_fto_send);
        counter_u64_free(rack_extended_rfo);
        counter_u64_free(rack_tlp_tot);
        counter_u64_free(rack_tlp_newdata);
        counter_u64_free(rack_tlp_retran);
        counter_u64_free(rack_tlp_retran_bytes);
        counter_u64_free(rack_to_tot);
        counter_u64_free(rack_saw_enobuf);
        counter_u64_free(rack_saw_enobuf_hw);
        counter_u64_free(rack_saw_enetunreach);
        counter_u64_free(rack_hot_alloc);
        counter_u64_free(rack_to_alloc);
        counter_u64_free(rack_to_alloc_hard);
        counter_u64_free(rack_to_alloc_emerg);
        counter_u64_free(rack_to_alloc_limited);
        counter_u64_free(rack_alloc_limited_conns);
        counter_u64_free(rack_split_limited);
        counter_u64_free(rack_multi_single_eq);
        counter_u64_free(rack_rxt_clamps_cwnd);
        counter_u64_free(rack_rxt_clamps_cwnd_uniq);
        counter_u64_free(rack_proc_non_comp_ack);
        counter_u64_free(rack_sack_proc_all);
        counter_u64_free(rack_sack_proc_restart);
        counter_u64_free(rack_sack_proc_short);
        counter_u64_free(rack_input_idle_reduces);
        counter_u64_free(rack_collapsed_win);
        counter_u64_free(rack_collapsed_win_rxt);
        counter_u64_free(rack_collapsed_win_rxt_bytes);
        counter_u64_free(rack_collapsed_win_seen);
        counter_u64_free(rack_try_scwnd);
        counter_u64_free(rack_persists_sends);
        counter_u64_free(rack_persists_acks);
        counter_u64_free(rack_persists_loss);
        counter_u64_free(rack_persists_lost_ends);
#ifdef INVARIANTS
        counter_u64_free(rack_adjust_map_bw);
#endif
        COUNTER_ARRAY_FREE(rack_out_size, TCP_MSS_ACCT_SIZE);
        COUNTER_ARRAY_FREE(rack_opts_arry, RACK_OPTS_SIZE);
}

static struct rack_sendmap *
rack_alloc(struct tcp_rack *rack)
{
        struct rack_sendmap *rsm;

        /*
         * First get the top of the list it in
         * theory is the "hottest" rsm we have,
         * possibly just freed by ack processing.
         */
        if (rack->rc_free_cnt > rack_free_cache) {
                rsm = TAILQ_FIRST(&rack->r_ctl.rc_free);
                TAILQ_REMOVE(&rack->r_ctl.rc_free, rsm, r_tnext);
                counter_u64_add(rack_hot_alloc, 1);
                rack->rc_free_cnt--;
                return (rsm);
        }
        /*
         * Once we get under our free cache we probably
         * no longer have a "hot" one available. Lets
         * get one from UMA.
         */
        rsm = uma_zalloc(rack_zone, M_NOWAIT);
        if (rsm) {
                rack->r_ctl.rc_num_maps_alloced++;
                counter_u64_add(rack_to_alloc, 1);
                return (rsm);
        }
        /*
         * Dig in to our aux rsm's (the last two) since
         * UMA failed to get us one.
         */
        if (rack->rc_free_cnt) {
                counter_u64_add(rack_to_alloc_emerg, 1);
                rsm = TAILQ_FIRST(&rack->r_ctl.rc_free);
                TAILQ_REMOVE(&rack->r_ctl.rc_free, rsm, r_tnext);
                rack->rc_free_cnt--;
                return (rsm);
        }
        return (NULL);
}

static struct rack_sendmap *
rack_alloc_full_limit(struct tcp_rack *rack)
{
        if ((V_tcp_map_entries_limit > 0) &&
            (rack->r_ctl.rc_num_maps_alloced >= V_tcp_map_entries_limit)) {
                counter_u64_add(rack_to_alloc_limited, 1);
                if (!rack->alloc_limit_reported) {
                        rack->alloc_limit_reported = 1;
                        counter_u64_add(rack_alloc_limited_conns, 1);
                }
                return (NULL);
        }
        return (rack_alloc(rack));
}

/* wrapper to allocate a sendmap entry, subject to a specific limit */
static struct rack_sendmap *
rack_alloc_limit(struct tcp_rack *rack, uint8_t limit_type)
{
        struct rack_sendmap *rsm;

        if (limit_type) {
                /* currently there is only one limit type */
                if (rack->r_ctl.rc_split_limit > 0 &&
                    rack->r_ctl.rc_num_split_allocs >= rack->r_ctl.rc_split_limit) {
                        counter_u64_add(rack_split_limited, 1);
                        if (!rack->alloc_limit_reported) {
                                rack->alloc_limit_reported = 1;
                                counter_u64_add(rack_alloc_limited_conns, 1);
                        }
                        return (NULL);
                }
        }

        /* allocate and mark in the limit type, if set */
        rsm = rack_alloc(rack);
        if (rsm != NULL && limit_type) {
                rsm->r_limit_type = limit_type;
                rack->r_ctl.rc_num_split_allocs++;
        }
        return (rsm);
}

static void
rack_free_trim(struct tcp_rack *rack)
{
        struct rack_sendmap *rsm;

        /*
         * Free up all the tail entries until
         * we get our list down to the limit.
         */
        while (rack->rc_free_cnt > rack_free_cache) {
                rsm = TAILQ_LAST(&rack->r_ctl.rc_free, rack_head);
                TAILQ_REMOVE(&rack->r_ctl.rc_free, rsm, r_tnext);
                rack->rc_free_cnt--;
                rack->r_ctl.rc_num_maps_alloced--;
                uma_zfree(rack_zone, rsm);
        }
}

static void
rack_free(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
        if (rsm->r_flags & RACK_APP_LIMITED) {
                KASSERT((rack->r_ctl.rc_app_limited_cnt > 0),
                    ("app_cnt %u, rsm %p", rack->r_ctl.rc_app_limited_cnt, rsm));
                rack->r_ctl.rc_app_limited_cnt--;
        }
        if (rsm->r_limit_type) {
                /* currently there is only one limit type */
                rack->r_ctl.rc_num_split_allocs--;
        }
        if (rsm == rack->r_ctl.rc_first_appl) {
                rack->r_ctl.cleared_app_ack_seq = rsm->r_end;
                rack->r_ctl.cleared_app_ack = 1;
                if (rack->r_ctl.rc_app_limited_cnt == 0)
                        rack->r_ctl.rc_first_appl = NULL;
                else
                        rack->r_ctl.rc_first_appl = tqhash_find(rack->r_ctl.tqh, rsm->r_nseq_appl);
        }
        if (rsm == rack->r_ctl.rc_resend)
                rack->r_ctl.rc_resend = NULL;
        if (rsm == rack->r_ctl.rc_end_appl)
                rack->r_ctl.rc_end_appl = NULL;
        if (rack->r_ctl.rc_tlpsend == rsm)
                rack->r_ctl.rc_tlpsend = NULL;
        if (rack->r_ctl.rc_sacklast == rsm)
                rack->r_ctl.rc_sacklast = NULL;
        memset(rsm, 0, sizeof(struct rack_sendmap));
        /* Make sure we are not going to overrun our count limit of 0xff */
        if ((rack->rc_free_cnt + 1) > RACK_FREE_CNT_MAX) {
                rack_free_trim(rack);
        }
        TAILQ_INSERT_HEAD(&rack->r_ctl.rc_free, rsm, r_tnext);
        rack->rc_free_cnt++;
}

static uint32_t
rack_get_measure_window(struct tcpcb *tp, struct tcp_rack *rack)
{
        uint64_t srtt, bw, len, tim;
        uint32_t segsiz, def_len, minl;

        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        def_len = rack_def_data_window * segsiz;
        if (rack->rc_gp_filled == 0) {
                /*
                 * We have no measurement (IW is in flight?) so
                 * we can only guess using our data_window sysctl
                 * value (usually 20MSS).
                 */
                return (def_len);
        }
        /*
         * Now we have a number of factors to consider.
         *
         * 1) We have a desired BDP which is usually
         *    at least 2.
         * 2) We have a minimum number of rtt's usually 1 SRTT
         *    but we allow it too to be more.
         * 3) We want to make sure a measurement last N useconds (if
         *    we have set rack_min_measure_usec.
         *
         * We handle the first concern here by trying to create a data
         * window of max(rack_def_data_window, DesiredBDP). The
         * second concern we handle in not letting the measurement
         * window end normally until at least the required SRTT's
         * have gone by which is done further below in
         * rack_enough_for_measurement(). Finally the third concern
         * we also handle here by calculating how long that time
         * would take at the current BW and then return the
         * max of our first calculation and that length. Note
         * that if rack_min_measure_usec is 0, we don't deal
         * with concern 3. Also for both Concern 1 and 3 an
         * application limited period could end the measurement
         * earlier.
         *
         * So lets calculate the BDP with the "known" b/w using
         * the SRTT as our rtt and then multiply it by the goal.
         */
        bw = rack_get_bw(rack);
        srtt = (uint64_t)tp->t_srtt;
        len = bw * srtt;
        len /= (uint64_t)HPTS_USEC_IN_SEC;
        len *= max(1, rack_goal_bdp);
        /* Now we need to round up to the nearest MSS */
        len = roundup(len, segsiz);
        if (rack_min_measure_usec) {
                /* Now calculate our min length for this b/w */
                tim = rack_min_measure_usec;
                minl = (tim * bw) / (uint64_t)HPTS_USEC_IN_SEC;
                if (minl == 0)
                        minl = 1;
                minl = roundup(minl, segsiz);
                if (len < minl)
                        len = minl;
        }
        /*
         * Now if we have a very small window we want
         * to attempt to get the window that is
         * as small as possible. This happens on
         * low b/w connections and we don't want to
         * span huge numbers of rtt's between measurements.
         *
         * We basically include 2 over our "MIN window" so
         * that the measurement can be shortened (possibly) by
         * an ack'ed packet.
         */
        if (len < def_len)
                return (max((uint32_t)len, ((MIN_GP_WIN+2) * segsiz)));
        else
                return (max((uint32_t)len, def_len));

}

static int
rack_enough_for_measurement(struct tcpcb *tp, struct tcp_rack *rack, tcp_seq th_ack, uint8_t *quality)
{
        uint32_t tim, srtts, segsiz;

        /*
         * Has enough time passed for the GP measurement to be valid?
         */
        if (SEQ_LT(th_ack, tp->gput_seq)) {
                /* Not enough bytes yet */
                return (0);
        }
        if ((tp->snd_max == tp->snd_una) ||
            (th_ack == tp->snd_max)){
                /*
                 * All is acked quality of all acked is
                 * usually low or medium, but we in theory could split
                 * all acked into two cases, where you got
                 * a signifigant amount of your window and
                 * where you did not. For now we leave it
                 * but it is something to contemplate in the
                 * future. The danger here is that delayed ack
                 * is effecting the last byte (which is a 50:50 chance).
                 */
                *quality = RACK_QUALITY_ALLACKED;
                return (1);
        }
        if (SEQ_GEQ(th_ack,  tp->gput_ack)) {
                /*
                 * We obtained our entire window of data we wanted
                 * no matter if we are in recovery or not then
                 * its ok since expanding the window does not
                 * make things fuzzy (or at least not as much).
                 */
                *quality = RACK_QUALITY_HIGH;
                return (1);
        }
        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        if (SEQ_LT(th_ack, tp->gput_ack) &&
            ((th_ack - tp->gput_seq) < max(rc_init_window(rack), (MIN_GP_WIN * segsiz)))) {
                /* Not enough bytes yet */
                return (0);
        }
        if (rack->r_ctl.rc_first_appl &&
            (SEQ_GEQ(th_ack, rack->r_ctl.rc_first_appl->r_end))) {
                /*
                 * We are up to the app limited send point
                 * we have to measure irrespective of the time..
                 */
                *quality = RACK_QUALITY_APPLIMITED;
                return (1);
        }
        /* Now what about time? */
        srtts = (rack->r_ctl.rc_gp_srtt * rack_min_srtts);
        tim = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time) - tp->gput_ts;
        if ((tim >= srtts) && (IN_RECOVERY(rack->rc_tp->t_flags) == 0)) {
                /*
                 * We do not allow a measurement if we are in recovery
                 * that would shrink the goodput window we wanted.
                 * This is to prevent cloudyness of when the last send
                 * was actually made.
                 */
                *quality = RACK_QUALITY_HIGH;
                return (1);
        }
        /* Nope not even a full SRTT has passed */
        return (0);
}

static void
rack_log_timely(struct tcp_rack *rack,
                uint32_t logged, uint64_t cur_bw, uint64_t low_bnd,
                uint64_t up_bnd, int line, uint8_t method)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = logged;
                log.u_bbr.flex2 = rack->rc_gp_timely_inc_cnt;
                log.u_bbr.flex2 <<= 4;
                log.u_bbr.flex2 |= rack->rc_gp_timely_dec_cnt;
                log.u_bbr.flex2 <<= 4;
                log.u_bbr.flex2 |= rack->rc_gp_incr;
                log.u_bbr.flex2 <<= 4;
                log.u_bbr.flex2 |= rack->rc_gp_bwred;
                log.u_bbr.flex3 = rack->rc_gp_incr;
                log.u_bbr.flex4 = rack->r_ctl.rack_per_of_gp_ss;
                log.u_bbr.flex5 = rack->r_ctl.rack_per_of_gp_ca;
                log.u_bbr.flex6 = rack->r_ctl.rack_per_of_gp_rec;
                log.u_bbr.flex7 = rack->rc_gp_bwred;
                log.u_bbr.flex8 = method;
                log.u_bbr.cur_del_rate = cur_bw;
                log.u_bbr.delRate = low_bnd;
                log.u_bbr.bw_inuse = up_bnd;
                log.u_bbr.rttProp = rack_get_bw(rack);
                log.u_bbr.pkt_epoch = line;
                log.u_bbr.pkts_out = rack->r_ctl.rc_rtt_diff;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.epoch = rack->r_ctl.rc_gp_srtt;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_prev_gp_srtt;
                log.u_bbr.cwnd_gain = rack->rc_dragged_bottom;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->rc_gp_saw_rec;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->rc_gp_saw_ss;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->rc_gp_saw_ca;
                log.u_bbr.lost = rack->r_ctl.rc_loss_count;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_TIMELY_WORK, 0,
                    0, &log, false, &tv);
        }
}

static int
rack_bw_can_be_raised(struct tcp_rack *rack, uint64_t cur_bw, uint64_t last_bw_est, uint16_t mult)
{
        /*
         * Before we increase we need to know if
         * the estimate just made was less than
         * our pacing goal (i.e. (cur_bw * mult) > last_bw_est)
         *
         * If we already are pacing at a fast enough
         * rate to push us faster there is no sense of
         * increasing.
         *
         * We first caculate our actual pacing rate (ss or ca multiplier
         * times our cur_bw).
         *
         * Then we take the last measured rate and multipy by our
         * maximum pacing overage to give us a max allowable rate.
         *
         * If our act_rate is smaller than our max_allowable rate
         * then we should increase. Else we should hold steady.
         *
         */
        uint64_t act_rate, max_allow_rate;

        if (rack_timely_no_stopping)
                return (1);

        if ((cur_bw == 0) || (last_bw_est == 0)) {
                /*
                 * Initial startup case or
                 * everything is acked case.
                 */
                rack_log_timely(rack,  mult, cur_bw, 0, 0,
                                __LINE__, 9);
                return (1);
        }
        if (mult <= 100) {
                /*
                 * We can always pace at or slightly above our rate.
                 */
                rack_log_timely(rack,  mult, cur_bw, 0, 0,
                                __LINE__, 9);
                return (1);
        }
        act_rate = cur_bw * (uint64_t)mult;
        act_rate /= 100;
        max_allow_rate = last_bw_est * ((uint64_t)rack_max_per_above + (uint64_t)100);
        max_allow_rate /= 100;
        if (act_rate < max_allow_rate) {
                /*
                 * Here the rate we are actually pacing at
                 * is smaller than 10% above our last measurement.
                 * This means we are pacing below what we would
                 * like to try to achieve (plus some wiggle room).
                 */
                rack_log_timely(rack,  mult, cur_bw, act_rate, max_allow_rate,
                                __LINE__, 9);
                return (1);
        } else {
                /*
                 * Here we are already pacing at least rack_max_per_above(10%)
                 * what we are getting back. This indicates most likely
                 * that we are being limited (cwnd/rwnd/app) and can't
                 * get any more b/w. There is no sense of trying to
                 * raise up the pacing rate its not speeding us up
                 * and we already are pacing faster than we are getting.
                 */
                rack_log_timely(rack,  mult, cur_bw, act_rate, max_allow_rate,
                                __LINE__, 8);
                return (0);
        }
}

static void
rack_validate_multipliers_at_or_above100(struct tcp_rack *rack)
{
        /*
         * When we drag bottom, we want to assure
         * that no multiplier is below 1.0, if so
         * we want to restore it to at least that.
         */
        if (rack->r_ctl.rack_per_of_gp_rec  < 100) {
                /* This is unlikely we usually do not touch recovery */
                rack->r_ctl.rack_per_of_gp_rec = 100;
        }
        if (rack->r_ctl.rack_per_of_gp_ca < 100) {
                rack->r_ctl.rack_per_of_gp_ca = 100;
        }
        if (rack->r_ctl.rack_per_of_gp_ss < 100) {
                rack->r_ctl.rack_per_of_gp_ss = 100;
        }
}

static void
rack_validate_multipliers_at_or_below_100(struct tcp_rack *rack)
{
        if (rack->r_ctl.rack_per_of_gp_ca > 100) {
                rack->r_ctl.rack_per_of_gp_ca = 100;
        }
        if (rack->r_ctl.rack_per_of_gp_ss > 100) {
                rack->r_ctl.rack_per_of_gp_ss = 100;
        }
}

static void
rack_increase_bw_mul(struct tcp_rack *rack, int timely_says, uint64_t cur_bw, uint64_t last_bw_est, int override)
{
        int32_t  calc, logged, plus;

        logged = 0;

        if (rack->rc_skip_timely)
                return;
        if (override) {
                /*
                 * override is passed when we are
                 * loosing b/w and making one last
                 * gasp at trying to not loose out
                 * to a new-reno flow.
                 */
                goto extra_boost;
        }
        /* In classic timely we boost by 5x if we have 5 increases in a row, lets not */
        if (rack->rc_gp_incr &&
            ((rack->rc_gp_timely_inc_cnt + 1) >= RACK_TIMELY_CNT_BOOST)) {
                /*
                 * Reset and get 5 strokes more before the boost. Note
                 * that the count is 0 based so we have to add one.
                 */
extra_boost:
                plus = (uint32_t)rack_gp_increase_per * RACK_TIMELY_CNT_BOOST;
                rack->rc_gp_timely_inc_cnt = 0;
        } else
                plus = (uint32_t)rack_gp_increase_per;
        /* Must be at least 1% increase for true timely increases */
        if ((plus < 1) &&
            ((rack->r_ctl.rc_rtt_diff <= 0) || (timely_says <= 0)))
                plus = 1;
        if (rack->rc_gp_saw_rec &&
            (rack->rc_gp_no_rec_chg == 0) &&
            rack_bw_can_be_raised(rack, cur_bw, last_bw_est,
                                  rack->r_ctl.rack_per_of_gp_rec)) {
                /* We have been in recovery ding it too */
                calc = rack->r_ctl.rack_per_of_gp_rec + plus;
                if (calc > 0xffff)
                        calc = 0xffff;
                logged |= 1;
                rack->r_ctl.rack_per_of_gp_rec = (uint16_t)calc;
                if (rack->r_ctl.rack_per_upper_bound_ca &&
                    (rack->rc_dragged_bottom == 0) &&
                    (rack->r_ctl.rack_per_of_gp_rec > rack->r_ctl.rack_per_upper_bound_ca))
                        rack->r_ctl.rack_per_of_gp_rec = rack->r_ctl.rack_per_upper_bound_ca;
        }
        if (rack->rc_gp_saw_ca &&
            (rack->rc_gp_saw_ss == 0) &&
            rack_bw_can_be_raised(rack, cur_bw, last_bw_est,
                                  rack->r_ctl.rack_per_of_gp_ca)) {
                /* In CA */
                calc = rack->r_ctl.rack_per_of_gp_ca + plus;
                if (calc > 0xffff)
                        calc = 0xffff;
                logged |= 2;
                rack->r_ctl.rack_per_of_gp_ca = (uint16_t)calc;
                if (rack->r_ctl.rack_per_upper_bound_ca &&
                    (rack->rc_dragged_bottom == 0) &&
                    (rack->r_ctl.rack_per_of_gp_ca > rack->r_ctl.rack_per_upper_bound_ca))
                        rack->r_ctl.rack_per_of_gp_ca = rack->r_ctl.rack_per_upper_bound_ca;
        }
        if (rack->rc_gp_saw_ss &&
            rack_bw_can_be_raised(rack, cur_bw, last_bw_est,
                                  rack->r_ctl.rack_per_of_gp_ss)) {
                /* In SS */
                calc = rack->r_ctl.rack_per_of_gp_ss + plus;
                if (calc > 0xffff)
                        calc = 0xffff;
                rack->r_ctl.rack_per_of_gp_ss = (uint16_t)calc;
                if (rack->r_ctl.rack_per_upper_bound_ss &&
                    (rack->rc_dragged_bottom == 0) &&
                    (rack->r_ctl.rack_per_of_gp_ss > rack->r_ctl.rack_per_upper_bound_ss))
                        rack->r_ctl.rack_per_of_gp_ss = rack->r_ctl.rack_per_upper_bound_ss;
                logged |= 4;
        }
        if (logged &&
            (rack->rc_gp_incr == 0)){
                /* Go into increment mode */
                rack->rc_gp_incr = 1;
                rack->rc_gp_timely_inc_cnt = 0;
        }
        if (rack->rc_gp_incr &&
            logged &&
            (rack->rc_gp_timely_inc_cnt < RACK_TIMELY_CNT_BOOST)) {
                rack->rc_gp_timely_inc_cnt++;
        }
        rack_log_timely(rack,  logged, plus, 0, 0,
                        __LINE__, 1);
}

static uint32_t
rack_get_decrease(struct tcp_rack *rack, uint32_t curper, int32_t rtt_diff)
{
        /*-
         * norm_grad = rtt_diff / minrtt;
         * new_per = curper * (1 - B * norm_grad)
         *
         * B = rack_gp_decrease_per (default 80%)
         * rtt_dif = input var current rtt-diff
         * curper = input var current percentage
         * minrtt = from rack filter
         *
         * In order to do the floating point calculations above we
         * do an integer conversion. The code looks confusing so let me
         * translate it into something that use more variables and
         * is clearer for us humans :)
         *
         * uint64_t norm_grad, inverse, reduce_by, final_result;
         * uint32_t perf;
         *
         * norm_grad = (((uint64_t)rtt_diff * 1000000) /
         *             (uint64_t)get_filter_small(&rack->r_ctl.rc_gp_min_rtt));
         * inverse = ((uint64_t)rack_gp_decrease * (uint64_t)1000000) * norm_grad;
         * inverse /= 1000000;
         * reduce_by = (1000000 - inverse);
         * final_result = (cur_per * reduce_by) / 1000000;
         * perf = (uint32_t)final_result;
         */
        uint64_t perf;

        perf = (((uint64_t)curper * ((uint64_t)1000000 -
                    ((uint64_t)rack_gp_decrease_per * (uint64_t)10000 *
                     (((uint64_t)rtt_diff * (uint64_t)1000000)/
                      (uint64_t)get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt)))/
                     (uint64_t)1000000)) /
                (uint64_t)1000000);
        if (perf > curper) {
                /* TSNH */
                perf = curper - 1;
        }
        return ((uint32_t)perf);
}

static uint32_t
rack_decrease_highrtt(struct tcp_rack *rack, uint32_t curper, uint32_t rtt)
{
        /*
         *                                   highrttthresh
         * result = curper * (1 - (B * ( 1 -  ------          ))
         *                                     gp_srtt
         *
         * B = rack_gp_decrease_per (default .8 i.e. 80)
         * highrttthresh = filter_min * rack_gp_rtt_maxmul
         */
        uint64_t perf;
        uint32_t highrttthresh;

        highrttthresh = get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) * rack_gp_rtt_maxmul;

        perf = (((uint64_t)curper * ((uint64_t)1000000 -
                                     ((uint64_t)rack_gp_decrease_per * ((uint64_t)1000000 -
                                        ((uint64_t)highrttthresh * (uint64_t)1000000) /
                                                    (uint64_t)rtt)) / 100)) /(uint64_t)1000000);
        if (tcp_bblogging_on(rack->rc_tp)) {
                uint64_t log1;

                log1 = rtt;
                log1 <<= 32;
                log1 |= highrttthresh;
                rack_log_timely(rack,
                                rack_gp_decrease_per,
                                (uint64_t)curper,
                                log1,
                                perf,
                                __LINE__,
                                15);
        }
        return (perf);
}

static void
rack_decrease_bw_mul(struct tcp_rack *rack, int timely_says, uint32_t rtt, int32_t rtt_diff)
{
        uint64_t logvar, logvar2, logvar3;
        uint32_t logged, new_per, ss_red, ca_red, rec_red, alt, val;

        if (rack->rc_skip_timely)
                return;
        if (rack->rc_gp_incr) {
                /* Turn off increment counting */
                rack->rc_gp_incr = 0;
                rack->rc_gp_timely_inc_cnt = 0;
        }
        ss_red = ca_red = rec_red = 0;
        logged = 0;
        /* Calculate the reduction value */
        if (rtt_diff < 0) {
                rtt_diff *= -1;
        }
        /* Must be at least 1% reduction */
        if (rack->rc_gp_saw_rec && (rack->rc_gp_no_rec_chg == 0)) {
                /* We have been in recovery ding it too */
                if (timely_says == 2) {
                        new_per = rack_decrease_highrtt(rack, rack->r_ctl.rack_per_of_gp_rec, rtt);
                        alt = rack_get_decrease(rack, rack->r_ctl.rack_per_of_gp_rec, rtt_diff);
                        if (alt < new_per)
                                val = alt;
                        else
                                val = new_per;
                } else
                         val = new_per = alt = rack_get_decrease(rack, rack->r_ctl.rack_per_of_gp_rec, rtt_diff);
                if (rack->r_ctl.rack_per_of_gp_rec > val) {
                        rec_red = (rack->r_ctl.rack_per_of_gp_rec - val);
                        rack->r_ctl.rack_per_of_gp_rec = (uint16_t)val;
                } else {
                        rack->r_ctl.rack_per_of_gp_rec = rack_per_lower_bound;
                        rec_red = 0;
                }
                if (rack_per_lower_bound > rack->r_ctl.rack_per_of_gp_rec)
                        rack->r_ctl.rack_per_of_gp_rec = rack_per_lower_bound;
                logged |= 1;
        }
        if (rack->rc_gp_saw_ss) {
                /* Sent in SS */
                if (timely_says == 2) {
                        new_per = rack_decrease_highrtt(rack, rack->r_ctl.rack_per_of_gp_ss, rtt);
                        alt = rack_get_decrease(rack, rack->r_ctl.rack_per_of_gp_ss, rtt_diff);
                        if (alt < new_per)
                                val = alt;
                        else
                                val = new_per;
                } else
                        val = new_per = alt = rack_get_decrease(rack, rack->r_ctl.rack_per_of_gp_ss, rtt_diff);
                if (rack->r_ctl.rack_per_of_gp_ss > new_per) {
                        ss_red = rack->r_ctl.rack_per_of_gp_ss - val;
                        rack->r_ctl.rack_per_of_gp_ss = (uint16_t)val;
                } else {
                        ss_red = new_per;
                        rack->r_ctl.rack_per_of_gp_ss = rack_per_lower_bound;
                        logvar = new_per;
                        logvar <<= 32;
                        logvar |= alt;
                        logvar2 = (uint32_t)rtt;
                        logvar2 <<= 32;
                        logvar2 |= (uint32_t)rtt_diff;
                        logvar3 = rack_gp_rtt_maxmul;
                        logvar3 <<= 32;
                        logvar3 |= get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt);
                        rack_log_timely(rack, timely_says,
                                        logvar2, logvar3,
                                        logvar, __LINE__, 10);
                }
                if (rack_per_lower_bound > rack->r_ctl.rack_per_of_gp_ss)
                        rack->r_ctl.rack_per_of_gp_ss = rack_per_lower_bound;
                logged |= 4;
        } else if (rack->rc_gp_saw_ca) {
                /* Sent in CA */
                if (timely_says == 2) {
                        new_per = rack_decrease_highrtt(rack, rack->r_ctl.rack_per_of_gp_ca, rtt);
                        alt = rack_get_decrease(rack, rack->r_ctl.rack_per_of_gp_ca, rtt_diff);
                        if (alt < new_per)
                                val = alt;
                        else
                                val = new_per;
                } else
                        val = new_per = alt = rack_get_decrease(rack, rack->r_ctl.rack_per_of_gp_ca, rtt_diff);
                if (rack->r_ctl.rack_per_of_gp_ca > val) {
                        ca_red = rack->r_ctl.rack_per_of_gp_ca - val;
                        rack->r_ctl.rack_per_of_gp_ca = (uint16_t)val;
                } else {
                        rack->r_ctl.rack_per_of_gp_ca = rack_per_lower_bound;
                        ca_red = 0;
                        logvar = new_per;
                        logvar <<= 32;
                        logvar |= alt;
                        logvar2 = (uint32_t)rtt;
                        logvar2 <<= 32;
                        logvar2 |= (uint32_t)rtt_diff;
                        logvar3 = rack_gp_rtt_maxmul;
                        logvar3 <<= 32;
                        logvar3 |= get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt);
                        rack_log_timely(rack, timely_says,
                                        logvar2, logvar3,
                                        logvar, __LINE__, 10);
                }
                if (rack_per_lower_bound > rack->r_ctl.rack_per_of_gp_ca)
                        rack->r_ctl.rack_per_of_gp_ca = rack_per_lower_bound;
                logged |= 2;
        }
        if (rack->rc_gp_timely_dec_cnt < 0x7) {
                rack->rc_gp_timely_dec_cnt++;
                if (rack_timely_dec_clear &&
                    (rack->rc_gp_timely_dec_cnt == rack_timely_dec_clear))
                        rack->rc_gp_timely_dec_cnt = 0;
        }
        logvar = ss_red;
        logvar <<= 32;
        logvar |= ca_red;
        rack_log_timely(rack,  logged, rec_red, rack_per_lower_bound, logvar,
                        __LINE__, 2);
}

static void
rack_log_rtt_shrinks(struct tcp_rack *rack, uint32_t us_cts,
                     uint32_t rtt, uint32_t line, uint8_t reas)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = line;
                log.u_bbr.flex2 = rack->r_ctl.rc_time_probertt_starts;
                log.u_bbr.flex3 = rack->r_ctl.rc_lower_rtt_us_cts;
                log.u_bbr.flex4 = rack->r_ctl.rack_per_of_gp_ss;
                log.u_bbr.flex5 = rtt;
                log.u_bbr.flex6 = rack->rc_highly_buffered;
                log.u_bbr.flex6 <<= 1;
                log.u_bbr.flex6 |= rack->forced_ack;
                log.u_bbr.flex6 <<= 1;
                log.u_bbr.flex6 |= rack->rc_gp_dyn_mul;
                log.u_bbr.flex6 <<= 1;
                log.u_bbr.flex6 |= rack->in_probe_rtt;
                log.u_bbr.flex6 <<= 1;
                log.u_bbr.flex6 |= rack->measure_saw_probe_rtt;
                log.u_bbr.flex7 = rack->r_ctl.rack_per_of_gp_probertt;
                log.u_bbr.pacing_gain = rack->r_ctl.rack_per_of_gp_ca;
                log.u_bbr.cwnd_gain = rack->r_ctl.rack_per_of_gp_rec;
                log.u_bbr.flex8 = reas;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.delRate = rack_get_bw(rack);
                log.u_bbr.cur_del_rate = rack->r_ctl.rc_highest_us_rtt;
                log.u_bbr.cur_del_rate <<= 32;
                log.u_bbr.cur_del_rate |= rack->r_ctl.rc_lowest_us_rtt;
                log.u_bbr.applimited = rack->r_ctl.rc_time_probertt_entered;
                log.u_bbr.pkts_out = rack->r_ctl.rc_rtt_diff;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.epoch = rack->r_ctl.rc_gp_srtt;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_prev_gp_srtt;
                log.u_bbr.pkt_epoch = rack->r_ctl.rc_lower_rtt_us_cts;
                log.u_bbr.delivered = rack->r_ctl.rc_target_probertt_flight;
                log.u_bbr.lost = get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt);
                log.u_bbr.rttProp = us_cts;
                log.u_bbr.rttProp <<= 32;
                log.u_bbr.rttProp |= rack->r_ctl.rc_entry_gp_rtt;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_RTT_SHRINKS, 0,
                    0, &log, false, &rack->r_ctl.act_rcv_time);
        }
}

static void
rack_set_prtt_target(struct tcp_rack *rack, uint32_t segsiz, uint32_t rtt)
{
        uint64_t bwdp;

        bwdp = rack_get_bw(rack);
        bwdp *= (uint64_t)rtt;
        bwdp /= (uint64_t)HPTS_USEC_IN_SEC;
        rack->r_ctl.rc_target_probertt_flight = roundup((uint32_t)bwdp, segsiz);
        if (rack->r_ctl.rc_target_probertt_flight < (segsiz * rack_timely_min_segs)) {
                /*
                 * A window protocol must be able to have 4 packets
                 * outstanding as the floor in order to function
                 * (especially considering delayed ack :D).
                 */
                rack->r_ctl.rc_target_probertt_flight = (segsiz * rack_timely_min_segs);
        }
}

static void
rack_enter_probertt(struct tcp_rack *rack, uint32_t us_cts)
{
        /**
         * ProbeRTT is a bit different in rack_pacing than in
         * BBR. It is like BBR in that it uses the lowering of
         * the RTT as a signal that we saw something new and
         * counts from there for how long between. But it is
         * different in that its quite simple. It does not
         * play with the cwnd and wait until we get down
         * to N segments outstanding and hold that for
         * 200ms. Instead it just sets the pacing reduction
         * rate to a set percentage (70 by default) and hold
         * that for a number of recent GP Srtt's.
         */
        uint32_t segsiz;

        rack->r_ctl.rc_lower_rtt_us_cts = us_cts;
        if (rack->rc_gp_dyn_mul == 0)
                return;

        if (rack->rc_tp->snd_max == rack->rc_tp->snd_una) {
                /* We are idle */
                return;
        }
        if ((rack->rc_tp->t_flags & TF_GPUTINPROG) &&
            SEQ_GT(rack->rc_tp->snd_una, rack->rc_tp->gput_seq)) {
                /*
                 * Stop the goodput now, the idea here is
                 * that future measurements with in_probe_rtt
                 * won't register if they are not greater so
                 * we want to get what info (if any) is available
                 * now.
                 */
                rack_do_goodput_measurement(rack->rc_tp, rack,
                                            rack->rc_tp->snd_una, __LINE__,
                                            RACK_QUALITY_PROBERTT);
        }
        rack->r_ctl.rack_per_of_gp_probertt = rack_per_of_gp_probertt;
        rack->r_ctl.rc_time_probertt_entered = us_cts;
        segsiz = min(ctf_fixed_maxseg(rack->rc_tp),
                     rack->r_ctl.rc_pace_min_segs);
        rack->in_probe_rtt = 1;
        rack->measure_saw_probe_rtt = 1;
        rack->r_ctl.rc_time_probertt_starts = 0;
        rack->r_ctl.rc_entry_gp_rtt = rack->r_ctl.rc_gp_srtt;
        if (rack_probertt_use_min_rtt_entry)
                rack_set_prtt_target(rack, segsiz, get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt));
        else
                rack_set_prtt_target(rack, segsiz, rack->r_ctl.rc_gp_srtt);
        rack_log_rtt_shrinks(rack,  us_cts,  get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt),
                             __LINE__, RACK_RTTS_ENTERPROBE);
}

static void
rack_exit_probertt(struct tcp_rack *rack, uint32_t us_cts)
{
        struct rack_sendmap *rsm;
        uint32_t segsiz;

        segsiz = min(ctf_fixed_maxseg(rack->rc_tp),
                     rack->r_ctl.rc_pace_min_segs);
        rack->in_probe_rtt = 0;
        if ((rack->rc_tp->t_flags & TF_GPUTINPROG) &&
            SEQ_GT(rack->rc_tp->snd_una, rack->rc_tp->gput_seq)) {
                /*
                 * Stop the goodput now, the idea here is
                 * that future measurements with in_probe_rtt
                 * won't register if they are not greater so
                 * we want to get what info (if any) is available
                 * now.
                 */
                rack_do_goodput_measurement(rack->rc_tp, rack,
                                            rack->rc_tp->snd_una, __LINE__,
                                            RACK_QUALITY_PROBERTT);
        } else if (rack->rc_tp->t_flags & TF_GPUTINPROG) {
                /*
                 * We don't have enough data to make a measurement.
                 * So lets just stop and start here after exiting
                 * probe-rtt. We probably are not interested in
                 * the results anyway.
                 */
                rack->rc_tp->t_flags &= ~TF_GPUTINPROG;
        }
        /*
         * Measurements through the current snd_max are going
         * to be limited by the slower pacing rate.
         *
         * We need to mark these as app-limited so we
         * don't collapse the b/w.
         */
        rsm = tqhash_max(rack->r_ctl.tqh);
        if (rsm && ((rsm->r_flags & RACK_APP_LIMITED) == 0)) {
                if (rack->r_ctl.rc_app_limited_cnt == 0)
                        rack->r_ctl.rc_end_appl = rack->r_ctl.rc_first_appl = rsm;
                else {
                        /*
                         * Go out to the end app limited and mark
                         * this new one as next and move the end_appl up
                         * to this guy.
                         */
                        if (rack->r_ctl.rc_end_appl)
                                rack->r_ctl.rc_end_appl->r_nseq_appl = rsm->r_start;
                        rack->r_ctl.rc_end_appl = rsm;
                }
                rsm->r_flags |= RACK_APP_LIMITED;
                rack->r_ctl.rc_app_limited_cnt++;
        }
        /*
         * Now, we need to examine our pacing rate multipliers.
         * If its under 100%, we need to kick it back up to
         * 100%. We also don't let it be over our "max" above
         * the actual rate i.e. 100% + rack_clamp_atexit_prtt.
         * Note setting clamp_atexit_prtt to 0 has the effect
         * of setting CA/SS to 100% always at exit (which is
         * the default behavior).
         */
        if (rack_probertt_clear_is) {
                rack->rc_gp_incr = 0;
                rack->rc_gp_bwred = 0;
                rack->rc_gp_timely_inc_cnt = 0;
                rack->rc_gp_timely_dec_cnt = 0;
        }
        /* Do we do any clamping at exit? */
        if (rack->rc_highly_buffered && rack_atexit_prtt_hbp) {
                rack->r_ctl.rack_per_of_gp_ca = rack_atexit_prtt_hbp;
                rack->r_ctl.rack_per_of_gp_ss = rack_atexit_prtt_hbp;
        }
        if ((rack->rc_highly_buffered == 0) && rack_atexit_prtt) {
                rack->r_ctl.rack_per_of_gp_ca = rack_atexit_prtt;
                rack->r_ctl.rack_per_of_gp_ss = rack_atexit_prtt;
        }
        /*
         * Lets set rtt_diff to 0, so that we will get a "boost"
         * after exiting.
         */
        rack->r_ctl.rc_rtt_diff = 0;

        /* Clear all flags so we start fresh */
        rack->rc_tp->t_bytes_acked = 0;
        rack->rc_tp->t_ccv.flags &= ~CCF_ABC_SENTAWND;
        /*
         * If configured to, set the cwnd and ssthresh to
         * our targets.
         */
        if (rack_probe_rtt_sets_cwnd) {
                uint64_t ebdp;
                uint32_t setto;

                /* Set ssthresh so we get into CA once we hit our target */
                if (rack_probertt_use_min_rtt_exit == 1) {
                        /* Set to min rtt */
                        rack_set_prtt_target(rack, segsiz,
                                             get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt));
                } else if (rack_probertt_use_min_rtt_exit == 2) {
                        /* Set to current gp rtt */
                        rack_set_prtt_target(rack, segsiz,
                                             rack->r_ctl.rc_gp_srtt);
                } else if (rack_probertt_use_min_rtt_exit == 3) {
                        /* Set to entry gp rtt */
                        rack_set_prtt_target(rack, segsiz,
                                             rack->r_ctl.rc_entry_gp_rtt);
                } else {
                        uint64_t sum;
                        uint32_t setval;

                        sum = rack->r_ctl.rc_entry_gp_rtt;
                        sum *= 10;
                        sum /= (uint64_t)(max(1, rack->r_ctl.rc_gp_srtt));
                        if (sum >= 20) {
                                /*
                                 * A highly buffered path needs
                                 * cwnd space for timely to work.
                                 * Lets set things up as if
                                 * we are heading back here again.
                                 */
                                setval = rack->r_ctl.rc_entry_gp_rtt;
                        } else if (sum >= 15) {
                                /*
                                 * Lets take the smaller of the
                                 * two since we are just somewhat
                                 * buffered.
                                 */
                                setval = rack->r_ctl.rc_gp_srtt;
                                if (setval > rack->r_ctl.rc_entry_gp_rtt)
                                        setval = rack->r_ctl.rc_entry_gp_rtt;
                        } else {
                                /*
                                 * Here we are not highly buffered
                                 * and should pick the min we can to
                                 * keep from causing loss.
                                 */
                                setval = get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt);
                        }
                        rack_set_prtt_target(rack, segsiz,
                                             setval);
                }
                if (rack_probe_rtt_sets_cwnd > 1) {
                        /* There is a percentage here to boost */
                        ebdp = rack->r_ctl.rc_target_probertt_flight;
                        ebdp *= rack_probe_rtt_sets_cwnd;
                        ebdp /= 100;
                        setto = rack->r_ctl.rc_target_probertt_flight + ebdp;
                } else
                        setto = rack->r_ctl.rc_target_probertt_flight;
                rack->rc_tp->snd_cwnd = roundup(setto, segsiz);
                if (rack->rc_tp->snd_cwnd < (segsiz * rack_timely_min_segs)) {
                        /* Enforce a min */
                        rack->rc_tp->snd_cwnd = segsiz * rack_timely_min_segs;
                }
                /* If we set in the cwnd also set the ssthresh point so we are in CA */
                rack->rc_tp->snd_ssthresh = (rack->rc_tp->snd_cwnd - 1);
        }
        rack_log_rtt_shrinks(rack,  us_cts,
                             get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt),
                             __LINE__, RACK_RTTS_EXITPROBE);
        /* Clear times last so log has all the info */
        rack->r_ctl.rc_probertt_sndmax_atexit = rack->rc_tp->snd_max;
        rack->r_ctl.rc_time_probertt_entered = us_cts;
        rack->r_ctl.rc_time_probertt_starts = rack->r_ctl.rc_lower_rtt_us_cts = us_cts;
        rack->r_ctl.rc_time_of_last_probertt = us_cts;
}

static void
rack_check_probe_rtt(struct tcp_rack *rack, uint32_t us_cts)
{
        /* Check in on probe-rtt */

        if (rack->rc_gp_filled == 0) {
                /* We do not do p-rtt unless we have gp measurements */
                return;
        }
        if (rack->in_probe_rtt) {
                uint64_t no_overflow;
                uint32_t endtime, must_stay;

                if (rack->r_ctl.rc_went_idle_time &&
                    ((us_cts - rack->r_ctl.rc_went_idle_time) > rack_min_probertt_hold)) {
                        /*
                         * We went idle during prtt, just exit now.
                         */
                        rack_exit_probertt(rack, us_cts);
                } else if (rack_probe_rtt_safety_val &&
                    TSTMP_GT(us_cts, rack->r_ctl.rc_time_probertt_entered) &&
                    ((us_cts - rack->r_ctl.rc_time_probertt_entered) > rack_probe_rtt_safety_val)) {
                        /*
                         * Probe RTT safety value triggered!
                         */
                        rack_log_rtt_shrinks(rack,  us_cts,
                                             get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt),
                                             __LINE__, RACK_RTTS_SAFETY);
                        rack_exit_probertt(rack, us_cts);
                }
                /* Calculate the max we will wait */
                endtime = rack->r_ctl.rc_time_probertt_entered + (rack->r_ctl.rc_gp_srtt * rack_max_drain_wait);
                if (rack->rc_highly_buffered)
                        endtime += (rack->r_ctl.rc_gp_srtt * rack_max_drain_hbp);
                /* Calculate the min we must wait */
                must_stay = rack->r_ctl.rc_time_probertt_entered + (rack->r_ctl.rc_gp_srtt * rack_must_drain);
                if ((ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked) > rack->r_ctl.rc_target_probertt_flight) &&
                    TSTMP_LT(us_cts, endtime)) {
                        uint32_t calc;
                        /* Do we lower more? */
no_exit:
                        if (TSTMP_GT(us_cts, rack->r_ctl.rc_time_probertt_entered))
                                calc = us_cts - rack->r_ctl.rc_time_probertt_entered;
                        else
                                calc = 0;
                        calc /= max(rack->r_ctl.rc_gp_srtt, 1);
                        if (calc) {
                                /* Maybe */
                                calc *= rack_per_of_gp_probertt_reduce;
                                if (calc > rack_per_of_gp_probertt)
                                        rack->r_ctl.rack_per_of_gp_probertt = rack_per_of_gp_lowthresh;
                                else
                                        rack->r_ctl.rack_per_of_gp_probertt = rack_per_of_gp_probertt - calc;
                                /* Limit it too */
                                if (rack->r_ctl.rack_per_of_gp_probertt < rack_per_of_gp_lowthresh)
                                        rack->r_ctl.rack_per_of_gp_probertt = rack_per_of_gp_lowthresh;
                        }
                        /* We must reach target or the time set */
                        return;
                }
                if (rack->r_ctl.rc_time_probertt_starts == 0) {
                        if ((TSTMP_LT(us_cts, must_stay) &&
                             rack->rc_highly_buffered) ||
                             (ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked) >
                              rack->r_ctl.rc_target_probertt_flight)) {
                                /* We are not past the must_stay time */
                                goto no_exit;
                        }
                        rack_log_rtt_shrinks(rack,  us_cts,
                                             get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt),
                                             __LINE__, RACK_RTTS_REACHTARGET);
                        rack->r_ctl.rc_time_probertt_starts = us_cts;
                        if (rack->r_ctl.rc_time_probertt_starts == 0)
                                rack->r_ctl.rc_time_probertt_starts = 1;
                        /* Restore back to our rate we want to pace at in prtt */
                        rack->r_ctl.rack_per_of_gp_probertt = rack_per_of_gp_probertt;
                }
                /*
                 * Setup our end time, some number of gp_srtts plus 200ms.
                 */
                no_overflow = ((uint64_t)rack->r_ctl.rc_gp_srtt *
                               (uint64_t)rack_probertt_gpsrtt_cnt_mul);
                if (rack_probertt_gpsrtt_cnt_div)
                        endtime = (uint32_t)(no_overflow / (uint64_t)rack_probertt_gpsrtt_cnt_div);
                else
                        endtime = 0;
                endtime += rack_min_probertt_hold;
                endtime += rack->r_ctl.rc_time_probertt_starts;
                if (TSTMP_GEQ(us_cts,  endtime)) {
                        /* yes, exit probertt */
                        rack_exit_probertt(rack, us_cts);
                }

        } else if ((rack->rc_skip_timely == 0) &&
                   (TSTMP_GT(us_cts, rack->r_ctl.rc_lower_rtt_us_cts)) &&
                   ((us_cts - rack->r_ctl.rc_lower_rtt_us_cts) >= rack_time_between_probertt)) {
                /* Go into probertt, its been too long since we went lower */
                rack_enter_probertt(rack, us_cts);
        }
}

static void
rack_update_multiplier(struct tcp_rack *rack, int32_t timely_says, uint64_t last_bw_est,
                       uint32_t rtt, int32_t rtt_diff)
{
        uint64_t cur_bw, up_bnd, low_bnd, subfr;
        uint32_t losses;

        if ((rack->rc_gp_dyn_mul == 0) ||
            (rack->use_fixed_rate) ||
            (rack->in_probe_rtt) ||
            (rack->rc_always_pace == 0)) {
                /* No dynamic GP multiplier in play */
                return;
        }
        losses = rack->r_ctl.rc_loss_count - rack->r_ctl.rc_loss_at_start;
        cur_bw = rack_get_bw(rack);
        /* Calculate our up and down range */
        up_bnd = rack->r_ctl.last_gp_comp_bw * (uint64_t)rack_gp_per_bw_mul_up;
        up_bnd /= 100;
        up_bnd += rack->r_ctl.last_gp_comp_bw;

        subfr = (uint64_t)rack->r_ctl.last_gp_comp_bw * (uint64_t)rack_gp_per_bw_mul_down;
        subfr /= 100;
        low_bnd = rack->r_ctl.last_gp_comp_bw - subfr;
        if ((timely_says == 2) && (rack->r_ctl.rc_no_push_at_mrtt)) {
                /*
                 * This is the case where our RTT is above
                 * the max target and we have been configured
                 * to just do timely no bonus up stuff in that case.
                 *
                 * There are two configurations, set to 1, and we
                 * just do timely if we are over our max. If its
                 * set above 1 then we slam the multipliers down
                 * to 100 and then decrement per timely.
                 */
                rack_log_timely(rack,  timely_says, cur_bw, low_bnd, up_bnd,
                                __LINE__, 3);
                if (rack->r_ctl.rc_no_push_at_mrtt > 1)
                        rack_validate_multipliers_at_or_below_100(rack);
                rack_decrease_bw_mul(rack, timely_says, rtt, rtt_diff);
        } else if ((timely_says != 0) && (last_bw_est < low_bnd) && !losses) {
                /*
                 * We are decreasing this is a bit complicated this
                 * means we are loosing ground. This could be
                 * because another flow entered and we are competing
                 * for b/w with it. This will push the RTT up which
                 * makes timely unusable unless we want to get shoved
                 * into a corner and just be backed off (the age
                 * old problem with delay based CC).
                 *
                 * On the other hand if it was a route change we
                 * would like to stay somewhat contained and not
                 * blow out the buffers.
                 */
                rack_log_timely(rack,  timely_says, cur_bw, low_bnd, up_bnd,
                                __LINE__, 3);
                rack->r_ctl.last_gp_comp_bw = cur_bw;
                if (rack->rc_gp_bwred == 0) {
                        /* Go into reduction counting */
                        rack->rc_gp_bwred = 1;
                        rack->rc_gp_timely_dec_cnt = 0;
                }
                if (rack->rc_gp_timely_dec_cnt < rack_timely_max_push_drop) {
                        /*
                         * Push another time with a faster pacing
                         * to try to gain back (we include override to
                         * get a full raise factor).
                         */
                        if ((rack->rc_gp_saw_ca && rack->r_ctl.rack_per_of_gp_ca <= rack_down_raise_thresh) ||
                            (rack->rc_gp_saw_ss && rack->r_ctl.rack_per_of_gp_ss <= rack_down_raise_thresh) ||
                            (timely_says == 0) ||
                            (rack_down_raise_thresh == 0)) {
                                /*
                                 * Do an override up in b/w if we were
                                 * below the threshold or if the threshold
                                 * is zero we always do the raise.
                                 */
                                rack_increase_bw_mul(rack, timely_says, cur_bw, last_bw_est, 1);
                        } else {
                                /* Log it stays the same */
                                rack_log_timely(rack,  0, last_bw_est, low_bnd, 0,
                                                __LINE__, 11);
                        }
                        rack->rc_gp_timely_dec_cnt++;
                        /* We are not incrementing really no-count */
                        rack->rc_gp_incr = 0;
                        rack->rc_gp_timely_inc_cnt = 0;
                } else {
                        /*
                         * Lets just use the RTT
                         * information and give up
                         * pushing.
                         */
                        goto use_timely;
                }
        } else if ((timely_says != 2) &&
                    !losses &&
                    (last_bw_est > up_bnd)) {
                /*
                 * We are increasing b/w lets keep going, updating
                 * our b/w and ignoring any timely input, unless
                 * of course we are at our max raise (if there is one).
                 */

                rack_log_timely(rack,  timely_says, cur_bw, low_bnd, up_bnd,
                                __LINE__, 3);
                rack->r_ctl.last_gp_comp_bw = cur_bw;
                if (rack->rc_gp_saw_ss &&
                    rack->r_ctl.rack_per_upper_bound_ss &&
                     (rack->r_ctl.rack_per_of_gp_ss == rack->r_ctl.rack_per_upper_bound_ss)) {
                            /*
                             * In cases where we can't go higher
                             * we should just use timely.
                             */
                            goto use_timely;
                }
                if (rack->rc_gp_saw_ca &&
                    rack->r_ctl.rack_per_upper_bound_ca &&
                    (rack->r_ctl.rack_per_of_gp_ca == rack->r_ctl.rack_per_upper_bound_ca)) {
                            /*
                             * In cases where we can't go higher
                             * we should just use timely.
                             */
                            goto use_timely;
                }
                rack->rc_gp_bwred = 0;
                rack->rc_gp_timely_dec_cnt = 0;
                /* You get a set number of pushes if timely is trying to reduce */
                if ((rack->rc_gp_incr < rack_timely_max_push_rise) || (timely_says == 0)) {
                        rack_increase_bw_mul(rack, timely_says, cur_bw, last_bw_est, 0);
                } else {
                        /* Log it stays the same */
                        rack_log_timely(rack,  0, last_bw_est, up_bnd, 0,
                            __LINE__, 12);
                }
                return;
        } else {
                /*
                 * We are staying between the lower and upper range bounds
                 * so use timely to decide.
                 */
                rack_log_timely(rack,  timely_says, cur_bw, low_bnd, up_bnd,
                                __LINE__, 3);
use_timely:
                if (timely_says) {
                        rack->rc_gp_incr = 0;
                        rack->rc_gp_timely_inc_cnt = 0;
                        if ((rack->rc_gp_timely_dec_cnt < rack_timely_max_push_drop) &&
                            !losses &&
                            (last_bw_est < low_bnd)) {
                                /* We are loosing ground */
                                rack_increase_bw_mul(rack, timely_says, cur_bw, last_bw_est, 0);
                                rack->rc_gp_timely_dec_cnt++;
                                /* We are not incrementing really no-count */
                                rack->rc_gp_incr = 0;
                                rack->rc_gp_timely_inc_cnt = 0;
                        } else
                                rack_decrease_bw_mul(rack, timely_says, rtt, rtt_diff);
                } else {
                        rack->rc_gp_bwred = 0;
                        rack->rc_gp_timely_dec_cnt = 0;
                        rack_increase_bw_mul(rack, timely_says, cur_bw, last_bw_est, 0);
                }
        }
}

static int32_t
rack_make_timely_judgement(struct tcp_rack *rack, uint32_t rtt, int32_t rtt_diff, uint32_t prev_rtt)
{
        int32_t timely_says;
        uint64_t log_mult, log_rtt_a_diff;

        log_rtt_a_diff = rtt;
        log_rtt_a_diff <<= 32;
        log_rtt_a_diff |= (uint32_t)rtt_diff;
        if (rtt >= (get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) *
                    rack_gp_rtt_maxmul)) {
                /* Reduce the b/w multiplier */
                timely_says = 2;
                log_mult = get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) * rack_gp_rtt_maxmul;
                log_mult <<= 32;
                log_mult |= prev_rtt;
                rack_log_timely(rack,  timely_says, log_mult,
                                get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt),
                                log_rtt_a_diff, __LINE__, 4);
        } else if (rtt <= (get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) +
                           ((get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) * rack_gp_rtt_minmul) /
                            max(rack_gp_rtt_mindiv , 1)))) {
                /* Increase the b/w multiplier */
                log_mult = get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) +
                        ((get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) * rack_gp_rtt_minmul) /
                         max(rack_gp_rtt_mindiv , 1));
                log_mult <<= 32;
                log_mult |= prev_rtt;
                timely_says = 0;
                rack_log_timely(rack,  timely_says, log_mult ,
                                get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt),
                                log_rtt_a_diff, __LINE__, 5);
        } else {
                /*
                 * Use a gradient to find it the timely gradient
                 * is:
                 * grad = rc_rtt_diff / min_rtt;
                 *
                 * anything below or equal to 0 will be
                 * a increase indication. Anything above
                 * zero is a decrease. Note we take care
                 * of the actual gradient calculation
                 * in the reduction (its not needed for
                 * increase).
                 */
                log_mult = prev_rtt;
                if (rtt_diff <= 0) {
                        /*
                         * Rttdiff is less than zero, increase the
                         * b/w multiplier (its 0 or negative)
                         */
                        timely_says = 0;
                        rack_log_timely(rack,  timely_says, log_mult,
                                        get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt), log_rtt_a_diff, __LINE__, 6);
                } else {
                        /* Reduce the b/w multiplier */
                        timely_says = 1;
                        rack_log_timely(rack,  timely_says, log_mult,
                                        get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt), log_rtt_a_diff, __LINE__, 7);
                }
        }
        return (timely_says);
}

static inline int
rack_in_gp_window(struct tcpcb *tp, struct rack_sendmap *rsm)
{
        if (SEQ_GEQ(rsm->r_start, tp->gput_seq) &&
            SEQ_LEQ(rsm->r_end, tp->gput_ack)) {
                /**
                 * This covers the case that the
                 * resent is completely inside
                 * the gp range or up to it.
                 *      |----------------|
                 *      |-----| <or>
                 *            |----|
                 *            <or>   |---|
                 */
                return (1);
        } else if (SEQ_LT(rsm->r_start, tp->gput_seq) &&
                   SEQ_GT(rsm->r_end, tp->gput_seq)){
                /**
                 * This covers the case of
                 *      |--------------|
                 *  |-------->|
                 */
                return (1);
        } else if (SEQ_GEQ(rsm->r_start, tp->gput_seq) &&
                   SEQ_LT(rsm->r_start, tp->gput_ack) &&
                   SEQ_GEQ(rsm->r_end, tp->gput_ack)) {

                /**
                 * This covers the case of
                 *      |--------------|
                 *              |-------->|
                 */
                return (1);
        }
        return (0);
}

static inline void
rack_mark_in_gp_win(struct tcpcb *tp, struct rack_sendmap *rsm)
{

        if ((tp->t_flags & TF_GPUTINPROG) == 0)
                return;
        /*
         * We have a Goodput measurement in progress. Mark
         * the send if its within the window. If its not
         * in the window make sure it does not have the mark.
         */
        if (rack_in_gp_window(tp, rsm))
                rsm->r_flags |= RACK_IN_GP_WIN;
        else
                rsm->r_flags &= ~RACK_IN_GP_WIN;
}

static inline void
rack_clear_gp_marks(struct tcpcb *tp, struct tcp_rack *rack)
{
        /* A GP measurement is ending, clear all marks on the send map*/
        struct rack_sendmap *rsm = NULL;

        rsm = tqhash_find(rack->r_ctl.tqh, tp->gput_seq);
        if (rsm == NULL) {
                rsm = tqhash_min(rack->r_ctl.tqh);
        }
        /* Nothing left? */
        while ((rsm != NULL) && (SEQ_GEQ(tp->gput_ack, rsm->r_start))){
                rsm->r_flags &= ~RACK_IN_GP_WIN;
                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
        }
}


static inline void
rack_tend_gp_marks(struct tcpcb *tp, struct tcp_rack *rack)
{
        struct rack_sendmap *rsm = NULL;

        if (tp->snd_una == tp->snd_max) {
                /* Nothing outstanding yet, nothing to do here */
                return;
        }
        if (SEQ_GT(tp->gput_seq, tp->snd_una)) {
                /*
                 * We are measuring ahead of some outstanding
                 * data. We need to walk through up until we get
                 * to gp_seq marking so that no rsm is set incorrectly
                 * with RACK_IN_GP_WIN.
                 */
                rsm = tqhash_min(rack->r_ctl.tqh);
                while (rsm != NULL) {
                        rack_mark_in_gp_win(tp, rsm);
                        if (SEQ_GEQ(rsm->r_end, tp->gput_seq))
                                break;
                        rsm = tqhash_next(rack->r_ctl.tqh, rsm);
                }
        }
        if (rsm == NULL) {
                /*
                 * Need to find the GP seq, if rsm is
                 * set we stopped as we hit it.
                 */
                rsm = tqhash_find(rack->r_ctl.tqh, tp->gput_seq);
                if (rsm == NULL)
                        return;
                rack_mark_in_gp_win(tp, rsm);
        }
        /*
         * Now we may need to mark already sent rsm, ahead of
         * gput_seq in the window since they may have been sent
         * *before* we started our measurment. The rsm, if non-null
         * has been marked (note if rsm would have been NULL we would have
         * returned in the previous block). So we go to the next, and continue
         * until we run out of entries or we exceed the gp_ack value.
         */
        rsm = tqhash_next(rack->r_ctl.tqh, rsm);
        while (rsm) {
                rack_mark_in_gp_win(tp, rsm);
                if (SEQ_GT(rsm->r_end, tp->gput_ack))
                        break;
                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
        }
}

static void
rack_log_gp_calc(struct tcp_rack *rack, uint32_t add_part, uint32_t sub_part, uint32_t srtt, uint64_t meas_bw, uint64_t utim, uint8_t meth, uint32_t line)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex1 = add_part;
                log.u_bbr.flex2 = sub_part;
                log.u_bbr.flex3 = rack_wma_divisor;
                log.u_bbr.flex4 = srtt;
                log.u_bbr.flex7 = (uint16_t)line;
                log.u_bbr.flex8 = meth;
                log.u_bbr.delRate = rack->r_ctl.gp_bw;
                log.u_bbr.cur_del_rate = meas_bw;
                log.u_bbr.rttProp = utim;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_THRESH_CALC, 0,
                    0, &log, false, &rack->r_ctl.act_rcv_time);
        }
}

static void
rack_do_goodput_measurement(struct tcpcb *tp, struct tcp_rack *rack,
                            tcp_seq th_ack, int line, uint8_t quality)
{
        uint64_t tim, bytes_ps, stim, utim;
        uint32_t segsiz, bytes, reqbytes, us_cts;
        int32_t gput, new_rtt_diff, timely_says;
        uint64_t  resid_bw, subpart = 0, addpart = 0, srtt;
        int did_add = 0;

        us_cts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        if (TSTMP_GEQ(us_cts, tp->gput_ts))
                tim = us_cts - tp->gput_ts;
        else
                tim = 0;
        if (rack->r_ctl.rc_gp_cumack_ts > rack->r_ctl.rc_gp_output_ts)
                stim = rack->r_ctl.rc_gp_cumack_ts - rack->r_ctl.rc_gp_output_ts;
        else
                stim = 0;
        /*
         * Use the larger of the send time or ack time. This prevents us
         * from being influenced by ack artifacts to come up with too
         * high of measurement. Note that since we are spanning over many more
         * bytes in most of our measurements hopefully that is less likely to
         * occur.
         */
        if (tim > stim)
                utim = max(tim, 1);
        else
                utim = max(stim, 1);
        reqbytes = min(rc_init_window(rack), (MIN_GP_WIN * segsiz));
        rack_log_gpset(rack, th_ack, us_cts, rack->r_ctl.rc_gp_cumack_ts, __LINE__, 3, NULL);
        if ((tim == 0) && (stim == 0)) {
                /*
                 * Invalid measurement time, maybe
                 * all on one ack/one send?
                 */
                bytes = 0;
                bytes_ps = 0;
                rack_log_pacing_delay_calc(rack, bytes_ps, reqbytes,
                                           0, 0, 0, 10, __LINE__, NULL, quality);
                goto skip_measurement;
        }
        if (rack->r_ctl.rc_gp_lowrtt == 0xffffffff) {
                /* We never made a us_rtt measurement? */
                bytes = 0;
                bytes_ps = 0;
                rack_log_pacing_delay_calc(rack, bytes_ps, reqbytes,
                                           0, 0, 0, 10, __LINE__, NULL, quality);
                goto skip_measurement;
        }
        /*
         * Calculate the maximum possible b/w this connection
         * could have. We base our calculation on the lowest
         * rtt we have seen during the measurement and the
         * largest rwnd the client has given us in that time. This
         * forms a BDP that is the maximum that we could ever
         * get to the client. Anything larger is not valid.
         *
         * I originally had code here that rejected measurements
         * where the time was less than 1/2 the latest us_rtt.
         * But after thinking on that I realized its wrong since
         * say you had a 150Mbps or even 1Gbps link, and you
         * were a long way away.. example I am in Europe (100ms rtt)
         * talking to my 1Gbps link in S.C. Now measuring say 150,000
         * bytes my time would be 1.2ms, and yet my rtt would say
         * the measurement was invalid the time was < 50ms. The
         * same thing is true for 150Mb (8ms of time).
         *
         * A better way I realized is to look at what the maximum
         * the connection could possibly do. This is gated on
         * the lowest RTT we have seen and the highest rwnd.
         * We should in theory never exceed that, if we are
         * then something on the path is storing up packets
         * and then feeding them all at once to our endpoint
         * messing up our measurement.
         */
        rack->r_ctl.last_max_bw = rack->r_ctl.rc_gp_high_rwnd;
        rack->r_ctl.last_max_bw *= HPTS_USEC_IN_SEC;
        rack->r_ctl.last_max_bw /= rack->r_ctl.rc_gp_lowrtt;
        if (SEQ_LT(th_ack, tp->gput_seq)) {
                /* No measurement can be made */
                bytes = 0;
                bytes_ps = 0;
                rack_log_pacing_delay_calc(rack, bytes_ps, reqbytes,
                                           0, 0, 0, 10, __LINE__, NULL, quality);
                goto skip_measurement;
        } else
                bytes = (th_ack - tp->gput_seq);
        bytes_ps = (uint64_t)bytes;
        /*
         * Don't measure a b/w for pacing unless we have gotten at least
         * an initial windows worth of data in this measurement interval.
         *
         * Small numbers of bytes get badly influenced by delayed ack and
         * other artifacts. Note we take the initial window or our
         * defined minimum GP (defaulting to 10 which hopefully is the
         * IW).
         */
        if (rack->rc_gp_filled == 0) {
                /*
                 * The initial estimate is special. We
                 * have blasted out an IW worth of packets
                 * without a real valid ack ts results. We
                 * then setup the app_limited_needs_set flag,
                 * this should get the first ack in (probably 2
                 * MSS worth) to be recorded as the timestamp.
                 * We thus allow a smaller number of bytes i.e.
                 * IW - 2MSS.
                 */
                reqbytes -= (2 * segsiz);
                /* Also lets fill previous for our first measurement to be neutral */
                rack->r_ctl.rc_prev_gp_srtt = rack->r_ctl.rc_gp_srtt;
        }
        if ((bytes_ps < reqbytes) || rack->app_limited_needs_set) {
                rack_log_pacing_delay_calc(rack, bytes_ps, reqbytes,
                                           rack->r_ctl.rc_app_limited_cnt,
                                           0, 0, 10, __LINE__, NULL, quality);
                goto skip_measurement;
        }
        /*
         * We now need to calculate the Timely like status so
         * we can update (possibly) the b/w multipliers.
         */
        new_rtt_diff = (int32_t)rack->r_ctl.rc_gp_srtt - (int32_t)rack->r_ctl.rc_prev_gp_srtt;
        if (rack->rc_gp_filled == 0) {
                /* No previous reading */
                rack->r_ctl.rc_rtt_diff = new_rtt_diff;
        } else {
                if (rack->measure_saw_probe_rtt == 0) {
                        /*
                         * We don't want a probertt to be counted
                         * since it will be negative incorrectly. We
                         * expect to be reducing the RTT when we
                         * pace at a slower rate.
                         */
                        rack->r_ctl.rc_rtt_diff -= (rack->r_ctl.rc_rtt_diff / 8);
                        rack->r_ctl.rc_rtt_diff += (new_rtt_diff / 8);
                }
        }
        timely_says = rack_make_timely_judgement(rack,
            rack->r_ctl.rc_gp_srtt,
            rack->r_ctl.rc_rtt_diff,
            rack->r_ctl.rc_prev_gp_srtt
        );
        bytes_ps *= HPTS_USEC_IN_SEC;
        bytes_ps /= utim;
        if (bytes_ps > rack->r_ctl.last_max_bw) {
                /*
                 * Something is on path playing
                 * since this b/w is not possible based
                 * on our BDP (highest rwnd and lowest rtt
                 * we saw in the measurement window).
                 *
                 * Another option here would be to
                 * instead skip the measurement.
                 */
                rack_log_pacing_delay_calc(rack, bytes, reqbytes,
                                           bytes_ps, rack->r_ctl.last_max_bw, 0,
                                           11, __LINE__, NULL, quality);
                bytes_ps = rack->r_ctl.last_max_bw;
        }
        /* We store gp for b/w in bytes per second */
        if (rack->rc_gp_filled == 0) {
                /* Initial measurement */
                if (bytes_ps) {
                        rack->r_ctl.gp_bw = bytes_ps;
                        rack->rc_gp_filled = 1;
                        rack->r_ctl.num_measurements = 1;
                        rack_set_pace_segments(rack->rc_tp, rack, __LINE__, NULL);
                } else {
                        rack_log_pacing_delay_calc(rack, bytes_ps, reqbytes,
                                                   rack->r_ctl.rc_app_limited_cnt,
                                                   0, 0, 10, __LINE__, NULL, quality);
                }
                if (tcp_in_hpts(rack->rc_tp) &&
                    (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT)) {
                        /*
                         * Ok we can't trust the pacer in this case
                         * where we transition from un-paced to paced.
                         * Or for that matter when the burst mitigation
                         * was making a wild guess and got it wrong.
                         * Stop the pacer and clear up all the aggregate
                         * delays etc.
                         */
                        tcp_hpts_remove(rack->rc_tp);
                        rack->r_ctl.rc_hpts_flags = 0;
                        rack->r_ctl.rc_last_output_to = 0;
                }
                did_add = 2;
        } else if (rack->r_ctl.num_measurements < RACK_REQ_AVG) {
                /* Still a small number run an average */
                rack->r_ctl.gp_bw += bytes_ps;
                addpart = rack->r_ctl.num_measurements;
                rack->r_ctl.num_measurements++;
                if (rack->r_ctl.num_measurements >= RACK_REQ_AVG) {
                        /* We have collected enough to move forward */
                        rack->r_ctl.gp_bw /= (uint64_t)rack->r_ctl.num_measurements;
                }
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                did_add = 3;
        } else {
                /*
                 * We want to take 1/wma of the goodput and add in to 7/8th
                 * of the old value weighted by the srtt. So if your measurement
                 * period is say 2 SRTT's long you would get 1/4 as the
                 * value, if it was like 1/2 SRTT then you would get 1/16th.
                 *
                 * But we must be careful not to take too much i.e. if the
                 * srtt is say 20ms and the measurement is taken over
                 * 400ms our weight would be 400/20 i.e. 20. On the
                 * other hand if we get a measurement over 1ms with a
                 * 10ms rtt we only want to take a much smaller portion.
                 */
                uint8_t meth;

                if (rack->r_ctl.num_measurements < 0xff) {
                        rack->r_ctl.num_measurements++;
                }
                srtt = (uint64_t)tp->t_srtt;
                if (srtt == 0) {
                        /*
                         * Strange why did t_srtt go back to zero?
                         */
                        if (rack->r_ctl.rc_rack_min_rtt)
                                srtt = rack->r_ctl.rc_rack_min_rtt;
                        else
                                srtt = HPTS_USEC_IN_MSEC;
                }
                /*
                 * XXXrrs: Note for reviewers, in playing with
                 * dynamic pacing I discovered this GP calculation
                 * as done originally leads to some undesired results.
                 * Basically you can get longer measurements contributing
                 * too much to the WMA. Thus I changed it if you are doing
                 * dynamic adjustments to only do the aportioned adjustment
                 * if we have a very small (time wise) measurement. Longer
                 * measurements just get there weight (defaulting to 1/8)
                 * add to the WMA. We may want to think about changing
                 * this to always do that for both sides i.e. dynamic
                 * and non-dynamic... but considering lots of folks
                 * were playing with this I did not want to change the
                 * calculation per.se. without your thoughts.. Lawerence?
                 * Peter??
                 */
                if (rack->rc_gp_dyn_mul == 0) {
                        subpart = rack->r_ctl.gp_bw * utim;
                        subpart /= (srtt * 8);
                        if (subpart < (rack->r_ctl.gp_bw / 2)) {
                                /*
                                 * The b/w update takes no more
                                 * away then 1/2 our running total
                                 * so factor it in.
                                 */
                                addpart = bytes_ps * utim;
                                addpart /= (srtt * 8);
                                meth = 1;
                        } else {
                                /*
                                 * Don't allow a single measurement
                                 * to account for more than 1/2 of the
                                 * WMA. This could happen on a retransmission
                                 * where utim becomes huge compared to
                                 * srtt (multiple retransmissions when using
                                 * the sending rate which factors in all the
                                 * transmissions from the first one).
                                 */
                                subpart = rack->r_ctl.gp_bw / 2;
                                addpart = bytes_ps / 2;
                                meth = 2;
                        }
                        rack_log_gp_calc(rack, addpart, subpart, srtt, bytes_ps, utim, meth, __LINE__);
                        resid_bw = rack->r_ctl.gp_bw - subpart;
                        rack->r_ctl.gp_bw = resid_bw + addpart;
                        did_add = 1;
                } else {
                        if ((utim / srtt) <= 1) {
                                /*
                                 * The b/w update was over a small period
                                 * of time. The idea here is to prevent a small
                                 * measurement time period from counting
                                 * too much. So we scale it based on the
                                 * time so it attributes less than 1/rack_wma_divisor
                                 * of its measurement.
                                 */
                                subpart = rack->r_ctl.gp_bw * utim;
                                subpart /= (srtt * rack_wma_divisor);
                                addpart = bytes_ps * utim;
                                addpart /= (srtt * rack_wma_divisor);
                                meth = 3;
                        } else {
                                /*
                                 * The scaled measurement was long
                                 * enough so lets just add in the
                                 * portion of the measurement i.e. 1/rack_wma_divisor
                                 */
                                subpart = rack->r_ctl.gp_bw / rack_wma_divisor;
                                addpart = bytes_ps / rack_wma_divisor;
                                meth = 4;
                        }
                        if ((rack->measure_saw_probe_rtt == 0) ||
                            (bytes_ps > rack->r_ctl.gp_bw)) {
                                /*
                                 * For probe-rtt we only add it in
                                 * if its larger, all others we just
                                 * add in.
                                 */
                                did_add = 1;
                                rack_log_gp_calc(rack, addpart, subpart, srtt, bytes_ps, utim, meth, __LINE__);
                                resid_bw = rack->r_ctl.gp_bw - subpart;
                                rack->r_ctl.gp_bw = resid_bw + addpart;
                        }
                }
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
        }
        /*
         * We only watch the growth of the GP during the initial startup
         * or first-slowstart that ensues. If we ever needed to watch
         * growth of gp outside of that period all we need to do is
         * remove the first clause of this if (rc_initial_ss_comp).
         */
        if ((rack->rc_initial_ss_comp == 0) &&
            (rack->r_ctl.num_measurements >= RACK_REQ_AVG)) {
                uint64_t gp_est;

                gp_est = bytes_ps;
                if (tcp_bblogging_on(rack->rc_tp)) {
                        union tcp_log_stackspecific log;
                        struct timeval tv;

                        memset(&log, 0, sizeof(log));
                        log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                        log.u_bbr.flex1 = rack->r_ctl.current_round;
                        log.u_bbr.flex2 = rack->r_ctl.last_rnd_of_gp_rise;
                        log.u_bbr.delRate = gp_est;
                        log.u_bbr.cur_del_rate = rack->r_ctl.last_gpest;
                        log.u_bbr.flex8 = 41;
                        (void)tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_CWND, 0,
                                            0, &log, false, NULL, __func__, __LINE__,&tv);
                }
                if ((rack->r_ctl.num_measurements == RACK_REQ_AVG) ||
                    (rack->r_ctl.last_gpest == 0)) {
                        /*
                         * The round we get our measurement averaging going
                         * is the base round so it always is the source point
                         * for when we had our first increment. From there on
                         * we only record the round that had a rise.
                         */
                        rack->r_ctl.last_rnd_of_gp_rise = rack->r_ctl.current_round;
                        rack->r_ctl.last_gpest = rack->r_ctl.gp_bw;
                } else if (gp_est >= rack->r_ctl.last_gpest) {
                        /*
                         * Test to see if its gone up enough
                         * to set the round count up to now. Note
                         * that on the seeding of the 4th measurement we
                         */
                        gp_est *= 1000;
                        gp_est /= rack->r_ctl.last_gpest;
                        if ((uint32_t)gp_est > rack->r_ctl.gp_gain_req) {
                                /*
                                 * We went up enough to record the round.
                                 */
                                if (tcp_bblogging_on(rack->rc_tp)) {
                                        union tcp_log_stackspecific log;
                                        struct timeval tv;

                                        memset(&log, 0, sizeof(log));
                                        log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                                        log.u_bbr.flex1 = rack->r_ctl.current_round;
                                        log.u_bbr.flex2 = (uint32_t)gp_est;
                                        log.u_bbr.flex3 = rack->r_ctl.gp_gain_req;
                                        log.u_bbr.delRate = gp_est;
                                        log.u_bbr.cur_del_rate = rack->r_ctl.last_gpest;
                                        log.u_bbr.flex8 = 42;
                                        (void)tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_CWND, 0,
                                                            0, &log, false, NULL, __func__, __LINE__,&tv);
                                }
                                rack->r_ctl.last_rnd_of_gp_rise = rack->r_ctl.current_round;
                                if (rack->r_ctl.use_gp_not_last == 1)
                                        rack->r_ctl.last_gpest = rack->r_ctl.gp_bw;
                                else
                                        rack->r_ctl.last_gpest = bytes_ps;
                        }
                }
        }
        if ((rack->gp_ready == 0) &&
            (rack->r_ctl.num_measurements >= rack->r_ctl.req_measurements)) {
                /* We have enough measurements now */
                rack->gp_ready = 1;
                if (rack->dgp_on ||
                    rack->rack_hibeta)
                        rack_set_cc_pacing(rack);
                if (rack->defer_options)
                        rack_apply_deferred_options(rack);
        }
        rack_log_pacing_delay_calc(rack, subpart, addpart, bytes_ps, stim,
                                   rack_get_bw(rack), 22, did_add, NULL, quality);
        /* We do not update any multipliers if we are in or have seen a probe-rtt */

        if ((rack->measure_saw_probe_rtt == 0) &&
            rack->rc_gp_rtt_set) {
                if (rack->rc_skip_timely == 0) {
                        rack_update_multiplier(rack, timely_says, bytes_ps,
                                               rack->r_ctl.rc_gp_srtt,
                                               rack->r_ctl.rc_rtt_diff);
                }
        }
        rack_log_pacing_delay_calc(rack, bytes, tim, bytes_ps, stim,
                                   rack_get_bw(rack), 3, line, NULL, quality);
        rack_log_pacing_delay_calc(rack,
                                   bytes, /* flex2 */
                                   tim, /* flex1 */
                                   bytes_ps, /* bw_inuse */
                                   rack->r_ctl.gp_bw, /* delRate */
                                   rack_get_lt_bw(rack), /* rttProp */
                                   20, line, NULL, 0);
        /* reset the gp srtt and setup the new prev */
        rack->r_ctl.rc_prev_gp_srtt = rack->r_ctl.rc_gp_srtt;
        /* Record the lost count for the next measurement */
        rack->r_ctl.rc_loss_at_start = rack->r_ctl.rc_loss_count;
skip_measurement:
        /*
         * We restart our diffs based on the gpsrtt in the
         * measurement window.
         */
        rack->rc_gp_rtt_set = 0;
        rack->rc_gp_saw_rec = 0;
        rack->rc_gp_saw_ca = 0;
        rack->rc_gp_saw_ss = 0;
        rack->rc_dragged_bottom = 0;
        if (quality == RACK_QUALITY_HIGH) {
                /*
                 * Gput in the stats world is in kbps where bytes_ps is
                 * bytes per second so we do ((x * 8)/ 1000).
                 */
                gput = (int32_t)((bytes_ps << 3) / (uint64_t)1000);
#ifdef STATS
                stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_GPUT,
                                         gput);
                /*
                 * XXXLAS: This is a temporary hack, and should be
                 * chained off VOI_TCP_GPUT when stats(9) grows an
                 * API to deal with chained VOIs.
                 */
                if (tp->t_stats_gput_prev > 0)
                        stats_voi_update_abs_s32(tp->t_stats,
                                                 VOI_TCP_GPUT_ND,
                                                 ((gput - tp->t_stats_gput_prev) * 100) /
                                                 tp->t_stats_gput_prev);
#endif
                tp->t_stats_gput_prev = gput;
        }
        tp->t_flags &= ~TF_GPUTINPROG;
        /*
         * Now are we app limited now and there is space from where we
         * were to where we want to go?
         *
         * We don't do the other case i.e. non-applimited here since
         * the next send will trigger us picking up the missing data.
         */
        if (rack->r_ctl.rc_first_appl &&
            TCPS_HAVEESTABLISHED(tp->t_state) &&
            rack->r_ctl.rc_app_limited_cnt &&
            (SEQ_GT(rack->r_ctl.rc_first_appl->r_start, th_ack)) &&
            ((rack->r_ctl.rc_first_appl->r_end - th_ack) >
             max(rc_init_window(rack), (MIN_GP_WIN * segsiz)))) {
                /*
                 * Yep there is enough outstanding to make a measurement here.
                 */
                struct rack_sendmap *rsm;

                rack->r_ctl.rc_gp_lowrtt = 0xffffffff;
                rack->r_ctl.rc_gp_high_rwnd = rack->rc_tp->snd_wnd;
                tp->gput_ts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
                rack->app_limited_needs_set = 0;
                tp->gput_seq = th_ack;
                if (rack->in_probe_rtt)
                        rack->measure_saw_probe_rtt = 1;
                else if ((rack->measure_saw_probe_rtt) &&
                         (SEQ_GEQ(tp->gput_seq, rack->r_ctl.rc_probertt_sndmax_atexit)))
                        rack->measure_saw_probe_rtt = 0;
                if ((rack->r_ctl.rc_first_appl->r_end - th_ack) >= rack_get_measure_window(tp, rack)) {
                        /* There is a full window to gain info from */
                        tp->gput_ack = tp->gput_seq + rack_get_measure_window(tp, rack);
                } else {
                        /* We can only measure up to the applimited point */
                        tp->gput_ack = tp->gput_seq + (rack->r_ctl.rc_first_appl->r_end - th_ack);
                        if ((tp->gput_ack - tp->gput_seq) < (MIN_GP_WIN * segsiz)) {
                                /*
                                 * We don't have enough to make a measurement.
                                 */
                                tp->t_flags &= ~TF_GPUTINPROG;
                                rack_log_pacing_delay_calc(rack, tp->gput_ack, tp->gput_seq,
                                                           0, 0, 0, 6, __LINE__, NULL, quality);
                                return;
                        }
                }
                if (tp->t_state >= TCPS_FIN_WAIT_1) {
                        /*
                         * We will get no more data into the SB
                         * this means we need to have the data available
                         * before we start a measurement.
                         */
                        if (sbavail(&tptosocket(tp)->so_snd) < (tp->gput_ack - tp->gput_seq)) {
                                /* Nope not enough data. */
                                return;
                        }
                }
                tp->t_flags |= TF_GPUTINPROG;
                /*
                 * Now we need to find the timestamp of the send at tp->gput_seq
                 * for the send based measurement.
                 */
                rack->r_ctl.rc_gp_cumack_ts = 0;
                rsm = tqhash_find(rack->r_ctl.tqh, tp->gput_seq);
                if (rsm) {
                        /* Ok send-based limit is set */
                        if (SEQ_LT(rsm->r_start, tp->gput_seq)) {
                                /*
                                 * Move back to include the earlier part
                                 * so our ack time lines up right (this may
                                 * make an overlapping measurement but thats
                                 * ok).
                                 */
                                tp->gput_seq = rsm->r_start;
                        }
                        if (rsm->r_flags & RACK_ACKED) {
                                struct rack_sendmap *nrsm;

                                tp->gput_ts = (uint32_t)rsm->r_ack_arrival;
                                tp->gput_seq = rsm->r_end;
                                nrsm = tqhash_next(rack->r_ctl.tqh, rsm);
                                if (nrsm)
                                        rsm = nrsm;
                                else {
                                        rack->app_limited_needs_set = 1;
                                }
                        } else
                                rack->app_limited_needs_set = 1;
                        /* We always go from the first send */
                        rack->r_ctl.rc_gp_output_ts = rsm->r_tim_lastsent[0];
                } else {
                        /*
                         * If we don't find the rsm due to some
                         * send-limit set the current time, which
                         * basically disables the send-limit.
                         */
                        struct timeval tv;

                        microuptime(&tv);
                        rack->r_ctl.rc_gp_output_ts = rack_to_usec_ts(&tv);
                }
                rack_tend_gp_marks(tp, rack);
                rack_log_pacing_delay_calc(rack,
                                           tp->gput_seq,
                                           tp->gput_ack,
                                           (uintptr_t)rsm,
                                           tp->gput_ts,
                                           (((uint64_t)rack->r_ctl.rc_app_limited_cnt << 32) | (uint64_t)rack->r_ctl.rc_gp_output_ts),
                                           9,
                                           __LINE__, rsm, quality);
                rack_log_gpset(rack, tp->gput_ack, 0, 0, __LINE__, 1, NULL);
        } else {
                /*
                 * To make sure proper timestamp merging occurs, we need to clear
                 * all GP marks if we don't start a measurement.
                 */
                rack_clear_gp_marks(tp, rack);
        }
}

/*
 * CC wrapper hook functions
 */
static void
rack_ack_received(struct tcpcb *tp, struct tcp_rack *rack, uint32_t th_ack, uint16_t nsegs,
    uint16_t type, int32_t post_recovery)
{
        uint32_t prior_cwnd, acked;
        struct tcp_log_buffer *lgb = NULL;
        uint8_t labc_to_use, quality;

        INP_WLOCK_ASSERT(tptoinpcb(tp));
        tp->t_ccv.nsegs = nsegs;
        acked = tp->t_ccv.bytes_this_ack = (th_ack - tp->snd_una);
        if ((post_recovery) && (rack->r_ctl.rc_early_recovery_segs)) {
                uint32_t max;

                max = rack->r_ctl.rc_early_recovery_segs * ctf_fixed_maxseg(tp);
                if (tp->t_ccv.bytes_this_ack > max) {
                        tp->t_ccv.bytes_this_ack = max;
                }
        }
#ifdef STATS
        stats_voi_update_abs_s32(tp->t_stats, VOI_TCP_CALCFRWINDIFF,
            ((int32_t)rack->r_ctl.cwnd_to_use) - tp->snd_wnd);
#endif
        if ((th_ack == tp->snd_max) && rack->lt_bw_up) {
                /*
                 * We will ack all the data, time to end any
                 * lt_bw_up we have running until something
                 * new is sent. Note we need to use the actual
                 * ack_rcv_time which with pacing may be different.
                 */
                uint64_t tmark;

                rack->r_ctl.lt_bw_bytes += (tp->snd_max - rack->r_ctl.lt_seq);
                rack->r_ctl.lt_seq = tp->snd_max;
                tmark = tcp_tv_to_lusec(&rack->r_ctl.act_rcv_time);
                if (tmark >= rack->r_ctl.lt_timemark) {
                        rack->r_ctl.lt_bw_time += (tmark - rack->r_ctl.lt_timemark);
                }
                rack->r_ctl.lt_timemark = tmark;
                rack->lt_bw_up = 0;
        }
        quality = RACK_QUALITY_NONE;
        if ((tp->t_flags & TF_GPUTINPROG) &&
            rack_enough_for_measurement(tp, rack, th_ack, &quality)) {
                /* Measure the Goodput */
                rack_do_goodput_measurement(tp, rack, th_ack, __LINE__, quality);
        }
        /* Which way our we limited, if not cwnd limited no advance in CA */
        if (tp->snd_cwnd <= tp->snd_wnd)
                tp->t_ccv.flags |= CCF_CWND_LIMITED;
        else
                tp->t_ccv.flags &= ~CCF_CWND_LIMITED;
        if (tp->snd_cwnd > tp->snd_ssthresh) {
                tp->t_bytes_acked += min(tp->t_ccv.bytes_this_ack,
                         nsegs * V_tcp_abc_l_var * ctf_fixed_maxseg(tp));
                /* For the setting of a window past use the actual scwnd we are using */
                if (tp->t_bytes_acked >= rack->r_ctl.cwnd_to_use) {
                        tp->t_bytes_acked -= rack->r_ctl.cwnd_to_use;
                        tp->t_ccv.flags |= CCF_ABC_SENTAWND;
                }
        } else {
                tp->t_ccv.flags &= ~CCF_ABC_SENTAWND;
                tp->t_bytes_acked = 0;
        }
        prior_cwnd = tp->snd_cwnd;
        if ((post_recovery == 0) || (rack_max_abc_post_recovery == 0) || rack->r_use_labc_for_rec ||
            (rack_client_low_buf && rack->client_bufferlvl &&
            (rack->client_bufferlvl < rack_client_low_buf)))
                labc_to_use = rack->rc_labc;
        else
                labc_to_use = rack_max_abc_post_recovery;
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex1 = th_ack;
                log.u_bbr.flex2 = tp->t_ccv.flags;
                log.u_bbr.flex3 = tp->t_ccv.bytes_this_ack;
                log.u_bbr.flex4 = tp->t_ccv.nsegs;
                log.u_bbr.flex5 = labc_to_use;
                log.u_bbr.flex6 = prior_cwnd;
                log.u_bbr.flex7 = 1;  /* always doing RFC6675 SACK */
                log.u_bbr.flex8 = 1;
                lgb = tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_CWND, 0,
                                     0, &log, false, NULL, __func__, __LINE__,&tv);
        }
        if (CC_ALGO(tp)->ack_received != NULL) {
                /* XXXLAS: Find a way to live without this */
                tp->t_ccv.curack = th_ack;
                tp->t_ccv.labc = labc_to_use;
                tp->t_ccv.flags |= CCF_USE_LOCAL_ABC;
                CC_ALGO(tp)->ack_received(&tp->t_ccv, type);
        }
        if (lgb) {
                lgb->tlb_stackinfo.u_bbr.flex6 = tp->snd_cwnd;
        }
        if (rack->r_must_retran) {
                if (SEQ_GEQ(th_ack, rack->r_ctl.rc_snd_max_at_rto)) {
                        /*
                         * We now are beyond the rxt point so lets disable
                         * the flag.
                         */
                        rack->r_ctl.rc_out_at_rto = 0;
                        rack->r_must_retran = 0;
                } else if ((prior_cwnd + ctf_fixed_maxseg(tp)) <= tp->snd_cwnd) {
                        /*
                         * Only decrement the rc_out_at_rto if the cwnd advances
                         * at least a whole segment. Otherwise next time the peer
                         * acks, we won't be able to send this generaly happens
                         * when we are in Congestion Avoidance.
                         */
                        if (acked <= rack->r_ctl.rc_out_at_rto){
                                rack->r_ctl.rc_out_at_rto -= acked;
                        } else {
                                rack->r_ctl.rc_out_at_rto = 0;
                        }
                }
        }
#ifdef STATS
        stats_voi_update_abs_ulong(tp->t_stats, VOI_TCP_LCWIN, rack->r_ctl.cwnd_to_use);
#endif
        if (rack->r_ctl.rc_rack_largest_cwnd < rack->r_ctl.cwnd_to_use) {
                rack->r_ctl.rc_rack_largest_cwnd = rack->r_ctl.cwnd_to_use;
        }
        if ((rack->rc_initial_ss_comp == 0) &&
            (tp->snd_cwnd >= tp->snd_ssthresh)) {
                /*
                 * The cwnd has grown beyond ssthresh we have
                 * entered ca and completed our first Slowstart.
                 */
                rack->rc_initial_ss_comp = 1;
        }
}

static void
tcp_rack_partialack(struct tcpcb *tp)
{
        struct tcp_rack *rack;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        INP_WLOCK_ASSERT(tptoinpcb(tp));
        /*
         * If we are doing PRR and have enough
         * room to send <or> we are pacing and prr
         * is disabled we will want to see if we
         * can send data (by setting r_wanted_output to
         * true).
         */
        if ((rack->r_ctl.rc_prr_sndcnt > 0) ||
            rack->rack_no_prr)
                rack->r_wanted_output = 1;
}

static void
rack_exit_recovery(struct tcpcb *tp, struct tcp_rack *rack, int how)
{
        /*
         * Now exit recovery.
         */
        EXIT_RECOVERY(tp->t_flags);
}

static void
rack_post_recovery(struct tcpcb *tp, uint32_t th_ack)
{
        struct tcp_rack *rack;
        uint32_t orig_cwnd;

        orig_cwnd = tp->snd_cwnd;
        INP_WLOCK_ASSERT(tptoinpcb(tp));
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        /* only alert CC if we alerted when we entered */
        if (CC_ALGO(tp)->post_recovery != NULL) {
                tp->t_ccv.curack = th_ack;
                CC_ALGO(tp)->post_recovery(&tp->t_ccv);
                if (tp->snd_cwnd < tp->snd_ssthresh) {
                        /*
                         * Rack has burst control and pacing
                         * so lets not set this any lower than
                         * snd_ssthresh per RFC-6582 (option 2).
                         */
                        tp->snd_cwnd = tp->snd_ssthresh;
                }
        }
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex1 = th_ack;
                log.u_bbr.flex2 = tp->t_ccv.flags;
                log.u_bbr.flex3 = tp->t_ccv.bytes_this_ack;
                log.u_bbr.flex4 = tp->t_ccv.nsegs;
                log.u_bbr.flex5 = V_tcp_abc_l_var;
                log.u_bbr.flex6 = orig_cwnd;
                log.u_bbr.flex7 = 1;  /* always doing RFC6675 SACK */
                log.u_bbr.pkts_out = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex8 = 2;
                tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_CWND, 0,
                               0, &log, false, NULL, __func__, __LINE__, &tv);
        }
        if ((rack->rack_no_prr == 0) &&
            (rack->no_prr_addback == 0) &&
            (rack->r_ctl.rc_prr_sndcnt > 0)) {
                /*
                 * Suck the next prr cnt back into cwnd, but
                 * only do that if we are not application limited.
                 */
                if (ctf_outstanding(tp) <= sbavail(&tptosocket(tp)->so_snd)) {
                        /*
                         * We are allowed to add back to the cwnd the amount we did
                         * not get out if:
                         * a) no_prr_addback is off.
                         * b) we are not app limited
                         * c) we are doing prr
                         * <and>
                         * d) it is bounded by rack_prr_addbackmax (if addback is 0, then none).
                         */
                        tp->snd_cwnd += min((ctf_fixed_maxseg(tp) * rack_prr_addbackmax),
                                            rack->r_ctl.rc_prr_sndcnt);
                }
                rack->r_ctl.rc_prr_sndcnt = 0;
                rack_log_to_prr(rack, 1, 0, __LINE__);
        }
        rack_log_to_prr(rack, 14, orig_cwnd, __LINE__);
        tp->snd_recover = tp->snd_una;
        if (rack->r_ctl.dsack_persist) {
                rack->r_ctl.dsack_persist--;
                if (rack->r_ctl.num_dsack && (rack->r_ctl.dsack_persist == 0)) {
                        rack->r_ctl.num_dsack = 0;
                }
                rack_log_dsack_event(rack, 1, __LINE__, 0, 0);
        }
        if (rack->rto_from_rec == 1) {
                rack->rto_from_rec = 0;
                if (rack->r_ctl.rto_ssthresh > tp->snd_ssthresh)
                        tp->snd_ssthresh = rack->r_ctl.rto_ssthresh;
        }
        rack_exit_recovery(tp, rack, 1);
}

static void
rack_cong_signal(struct tcpcb *tp, uint32_t type, uint32_t ack, int line)
{
        struct tcp_rack *rack;
        uint32_t ssthresh_enter, cwnd_enter, in_rec_at_entry, orig_cwnd;

        INP_WLOCK_ASSERT(tptoinpcb(tp));
#ifdef STATS
        stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_CSIG, type);
#endif
        if (IN_RECOVERY(tp->t_flags) == 0) {
                in_rec_at_entry = 0;
                ssthresh_enter = tp->snd_ssthresh;
                cwnd_enter = tp->snd_cwnd;
        } else
                in_rec_at_entry = 1;
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        switch (type) {
        case CC_NDUPACK:
                tp->t_flags &= ~TF_WASFRECOVERY;
                tp->t_flags &= ~TF_WASCRECOVERY;
                if (!IN_FASTRECOVERY(tp->t_flags)) {
                        /* Check if this is the end of the initial Start-up i.e. initial slow-start */
                        if (rack->rc_initial_ss_comp == 0) {
                                /* Yep it is the end of the initial slowstart */
                                rack->rc_initial_ss_comp = 1;
                        }
                        rack->r_ctl.rc_prr_delivered = 0;
                        rack->r_ctl.rc_prr_out = 0;
                        rack->r_fast_output = 0;
                        rack->r_ctl.recovery_rxt_cnt = 0;
                        if (rack->rack_no_prr == 0) {
                                rack->r_ctl.rc_prr_sndcnt = ctf_fixed_maxseg(tp);
                                rack_log_to_prr(rack, 2, in_rec_at_entry, line);
                        }
                        rack->r_ctl.rc_prr_recovery_fs = tp->snd_max - tp->snd_una;
                        tp->snd_recover = tp->snd_max;
                        if (tp->t_flags2 & TF2_ECN_PERMIT)
                                tp->t_flags2 |= TF2_ECN_SND_CWR;
                }
                break;
        case CC_ECN:
                if (!IN_CONGRECOVERY(tp->t_flags) ||
                    /*
                     * Allow ECN reaction on ACK to CWR, if
                     * that data segment was also CE marked.
                     */
                    SEQ_GEQ(ack, tp->snd_recover)) {
                        EXIT_CONGRECOVERY(tp->t_flags);
                        KMOD_TCPSTAT_INC(tcps_ecn_rcwnd);
                        rack->r_fast_output = 0;
                        tp->snd_recover = tp->snd_max + 1;
                        if (tp->t_flags2 & TF2_ECN_PERMIT)
                                tp->t_flags2 |= TF2_ECN_SND_CWR;
                }
                break;
        case CC_RTO:
                tp->t_dupacks = 0;
                tp->t_bytes_acked = 0;
                rack->r_fast_output = 0;
                if (IN_RECOVERY(tp->t_flags))
                        rack_exit_recovery(tp, rack, 2);
                orig_cwnd = tp->snd_cwnd;
                rack_log_to_prr(rack, 16, orig_cwnd, line);
                if (CC_ALGO(tp)->cong_signal == NULL) {
                        /* TSNH */
                        tp->snd_ssthresh = max(2,
                            min(tp->snd_wnd, rack->r_ctl.cwnd_to_use) / 2 /
                            ctf_fixed_maxseg(tp)) * ctf_fixed_maxseg(tp);
                        tp->snd_cwnd = ctf_fixed_maxseg(tp);
                }
                if (tp->t_flags2 & TF2_ECN_PERMIT)
                        tp->t_flags2 |= TF2_ECN_SND_CWR;
                break;
        case CC_RTO_ERR:
                KMOD_TCPSTAT_INC(tcps_sndrexmitbad);
                /* RTO was unnecessary, so reset everything. */
                tp->snd_cwnd = tp->snd_cwnd_prev;
                tp->snd_ssthresh = tp->snd_ssthresh_prev;
                tp->snd_recover = tp->snd_recover_prev;
                if (tp->t_flags & TF_WASFRECOVERY) {
                        ENTER_FASTRECOVERY(tp->t_flags);
                        tp->t_flags &= ~TF_WASFRECOVERY;
                }
                if (tp->t_flags & TF_WASCRECOVERY) {
                        ENTER_CONGRECOVERY(tp->t_flags);
                        tp->t_flags &= ~TF_WASCRECOVERY;
                }
                tp->snd_nxt = tp->snd_max;
                tp->t_badrxtwin = 0;
                break;
        }
        if ((CC_ALGO(tp)->cong_signal != NULL) &&
            (type != CC_RTO)){
                tp->t_ccv.curack = ack;
                CC_ALGO(tp)->cong_signal(&tp->t_ccv, type);
        }
        if ((in_rec_at_entry == 0) && IN_RECOVERY(tp->t_flags)) {
                rack_log_to_prr(rack, 15, cwnd_enter, line);
                rack->r_ctl.dsack_byte_cnt = 0;
                rack->r_ctl.retran_during_recovery = 0;
                rack->r_ctl.rc_cwnd_at_erec = cwnd_enter;
                rack->r_ctl.rc_ssthresh_at_erec = ssthresh_enter;
                rack->r_ent_rec_ns = 1;
        }
}

static inline void
rack_cc_after_idle(struct tcp_rack *rack, struct tcpcb *tp)
{
        uint32_t i_cwnd;

        INP_WLOCK_ASSERT(tptoinpcb(tp));

        if (CC_ALGO(tp)->after_idle != NULL)
                CC_ALGO(tp)->after_idle(&tp->t_ccv);

        if (tp->snd_cwnd == 1)
                i_cwnd = tp->t_maxseg;          /* SYN(-ACK) lost */
        else
                i_cwnd = rc_init_window(rack);

        /*
         * Being idle is no different than the initial window. If the cc
         * clamps it down below the initial window raise it to the initial
         * window.
         */
        if (tp->snd_cwnd < i_cwnd) {
                tp->snd_cwnd = i_cwnd;
        }
}

/*
 * Indicate whether this ack should be delayed.  We can delay the ack if
 * following conditions are met:
 *      - There is no delayed ack timer in progress.
 *      - Our last ack wasn't a 0-sized window. We never want to delay
 *        the ack that opens up a 0-sized window.
 *      - LRO wasn't used for this segment. We make sure by checking that the
 *        segment size is not larger than the MSS.
 *      - Delayed acks are enabled or this is a half-synchronized T/TCP
 *        connection.
 */
#define DELAY_ACK(tp, tlen)                      \
        (((tp->t_flags & TF_RXWIN0SENT) == 0) && \
        ((tp->t_flags & TF_DELACK) == 0) &&      \
        (tlen <= tp->t_maxseg) &&                \
        (tp->t_delayed_ack || (tp->t_flags & TF_NEEDSYN)))

static struct rack_sendmap *
rack_find_lowest_rsm(struct tcp_rack *rack)
{
        struct rack_sendmap *rsm;

        /*
         * Walk the time-order transmitted list looking for an rsm that is
         * not acked. This will be the one that was sent the longest time
         * ago that is still outstanding.
         */
        TAILQ_FOREACH(rsm, &rack->r_ctl.rc_tmap, r_tnext) {
                if (rsm->r_flags & RACK_ACKED) {
                        continue;
                }
                goto finish;
        }
finish:
        return (rsm);
}

static struct rack_sendmap *
rack_find_high_nonack(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
        struct rack_sendmap *prsm;

        /*
         * Walk the sequence order list backward until we hit and arrive at
         * the highest seq not acked. In theory when this is called it
         * should be the last segment (which it was not).
         */
        prsm = rsm;

        TQHASH_FOREACH_REVERSE_FROM(prsm, rack->r_ctl.tqh) {
                if (prsm->r_flags & (RACK_ACKED | RACK_HAS_FIN)) {
                        continue;
                }
                return (prsm);
        }
        return (NULL);
}

static uint32_t
rack_calc_thresh_rack(struct tcp_rack *rack, uint32_t srtt, uint32_t cts, int line, int log_allowed)
{
        int32_t lro;
        uint32_t thresh;

        /*
         * lro is the flag we use to determine if we have seen reordering.
         * If it gets set we have seen reordering. The reorder logic either
         * works in one of two ways:
         *
         * If reorder-fade is configured, then we track the last time we saw
         * re-ordering occur. If we reach the point where enough time as
         * passed we no longer consider reordering as occurring.
         *
         * Or if reorder-face is 0, then once we see reordering we consider
         * the connection to alway be subject to reordering and just set lro
         * to 1.
         *
         * In the end if lro is non-zero we add the extra time for
         * reordering in.
         */
        if (srtt == 0)
                srtt = 1;
        if (rack->r_ctl.rc_reorder_ts) {
                if (rack->r_ctl.rc_reorder_fade) {
                        if (SEQ_GEQ(cts, rack->r_ctl.rc_reorder_ts)) {
                                lro = cts - rack->r_ctl.rc_reorder_ts;
                                if (lro == 0) {
                                        /*
                                         * No time as passed since the last
                                         * reorder, mark it as reordering.
                                         */
                                        lro = 1;
                                }
                        } else {
                                /* Negative time? */
                                lro = 0;
                        }
                        if (lro > rack->r_ctl.rc_reorder_fade) {
                                /* Turn off reordering seen too */
                                rack->r_ctl.rc_reorder_ts = 0;
                                lro = 0;
                        }
                } else {
                        /* Reodering does not fade */
                        lro = 1;
                }
        } else {
                lro = 0;
        }
        if (rack->rc_rack_tmr_std_based == 0) {
                thresh = srtt + rack->r_ctl.rc_pkt_delay;
        } else {
                /* Standards based pkt-delay is 1/4 srtt */
                thresh = srtt +  (srtt >> 2);
        }
        if (lro && (rack->rc_rack_tmr_std_based == 0)) {
                /* It must be set, if not you get 1/4 rtt */
                if (rack->r_ctl.rc_reorder_shift)
                        thresh += (srtt >> rack->r_ctl.rc_reorder_shift);
                else
                        thresh += (srtt >> 2);
        }
        if (rack->rc_rack_use_dsack &&
            lro &&
            (rack->r_ctl.num_dsack > 0)) {
                /*
                 * We only increase the reordering window if we
                 * have seen reordering <and> we have a DSACK count.
                 */
                thresh += rack->r_ctl.num_dsack * (srtt >> 2);
                if (log_allowed)
                        rack_log_dsack_event(rack, 4, line, srtt, thresh);
        }
        /* SRTT * 2 is the ceiling */
        if (thresh > (srtt * 2)) {
                thresh = srtt * 2;
        }
        /* And we don't want it above the RTO max either */
        if (thresh > rack_rto_max) {
                thresh = rack_rto_max;
        }
        if (log_allowed)
                rack_log_dsack_event(rack, 6, line,  srtt, thresh);
        return (thresh);
}

static uint32_t
rack_calc_thresh_tlp(struct tcpcb *tp, struct tcp_rack *rack,
                     struct rack_sendmap *rsm, uint32_t srtt)
{
        struct rack_sendmap *prsm;
        uint32_t thresh, len;
        int segsiz;

        if (srtt == 0)
                srtt = 1;
        if (rack->r_ctl.rc_tlp_threshold)
                thresh = srtt + (srtt / rack->r_ctl.rc_tlp_threshold);
        else
                thresh = (srtt * 2);

        /* Get the previous sent packet, if any */
        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        len = rsm->r_end - rsm->r_start;
        if (rack->rack_tlp_threshold_use == TLP_USE_ID) {
                /* Exactly like the ID */
                if (((tp->snd_max - tp->snd_una) - rack->r_ctl.rc_sacked + rack->r_ctl.rc_holes_rxt) <= segsiz) {
                        uint32_t alt_thresh;
                        /*
                         * Compensate for delayed-ack with the d-ack time.
                         */
                        alt_thresh = srtt + (srtt / 2) + rack_delayed_ack_time;
                        if (alt_thresh > thresh)
                                thresh = alt_thresh;
                }
        } else if (rack->rack_tlp_threshold_use == TLP_USE_TWO_ONE) {
                /* 2.1 behavior */
                prsm = TAILQ_PREV(rsm, rack_head, r_tnext);
                if (prsm && (len <= segsiz)) {
                        /*
                         * Two packets outstanding, thresh should be (2*srtt) +
                         * possible inter-packet delay (if any).
                         */
                        uint32_t inter_gap = 0;
                        int idx, nidx;

                        idx = rsm->r_rtr_cnt - 1;
                        nidx = prsm->r_rtr_cnt - 1;
                        if (rsm->r_tim_lastsent[nidx] >= prsm->r_tim_lastsent[idx]) {
                                /* Yes it was sent later (or at the same time) */
                                inter_gap = rsm->r_tim_lastsent[idx] - prsm->r_tim_lastsent[nidx];
                        }
                        thresh += inter_gap;
                } else if (len <= segsiz) {
                        /*
                         * Possibly compensate for delayed-ack.
                         */
                        uint32_t alt_thresh;

                        alt_thresh = srtt + (srtt / 2) + rack_delayed_ack_time;
                        if (alt_thresh > thresh)
                                thresh = alt_thresh;
                }
        } else if (rack->rack_tlp_threshold_use == TLP_USE_TWO_TWO) {
                /* 2.2 behavior */
                if (len <= segsiz) {
                        uint32_t alt_thresh;
                        /*
                         * Compensate for delayed-ack with the d-ack time.
                         */
                        alt_thresh = srtt + (srtt / 2) + rack_delayed_ack_time;
                        if (alt_thresh > thresh)
                                thresh = alt_thresh;
                }
        }
        /* Not above an RTO */
        if (thresh > tp->t_rxtcur) {
                thresh = tp->t_rxtcur;
        }
        /* Not above a RTO max */
        if (thresh > rack_rto_max) {
                thresh = rack_rto_max;
        }
        /* Apply user supplied min TLP */
        if (thresh < rack_tlp_min) {
                thresh = rack_tlp_min;
        }
        return (thresh);
}

static uint32_t
rack_grab_rtt(struct tcpcb *tp, struct tcp_rack *rack)
{
        /*
         * We want the rack_rtt which is the
         * last rtt we measured. However if that
         * does not exist we fallback to the srtt (which
         * we probably will never do) and then as a last
         * resort we use RACK_INITIAL_RTO if no srtt is
         * yet set.
         */
        if (rack->rc_rack_rtt)
                return (rack->rc_rack_rtt);
        else if (tp->t_srtt == 0)
                return (RACK_INITIAL_RTO);
        return (tp->t_srtt);
}

static struct rack_sendmap *
rack_check_recovery_mode(struct tcpcb *tp, uint32_t tsused)
{
        /*
         * Check to see that we don't need to fall into recovery. We will
         * need to do so if our oldest transmit is past the time we should
         * have had an ack.
         */
        struct tcp_rack *rack;
        struct rack_sendmap *rsm;
        int32_t idx;
        uint32_t srtt, thresh;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (tqhash_empty(rack->r_ctl.tqh)) {
                return (NULL);
        }
        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
        if (rsm == NULL)
                return (NULL);


        if (rsm->r_flags & RACK_ACKED) {
                rsm = rack_find_lowest_rsm(rack);
                if (rsm == NULL)
                        return (NULL);
        }
        idx = rsm->r_rtr_cnt - 1;
        srtt = rack_grab_rtt(tp, rack);
        thresh = rack_calc_thresh_rack(rack, srtt, tsused, __LINE__, 1);
        if (TSTMP_LT(tsused, ((uint32_t)rsm->r_tim_lastsent[idx]))) {
                return (NULL);
        }
        if ((tsused - ((uint32_t)rsm->r_tim_lastsent[idx])) < thresh) {
                return (NULL);
        }
        /* Ok if we reach here we are over-due and this guy can be sent */
        rack_cong_signal(tp, CC_NDUPACK, tp->snd_una, __LINE__);
        return (rsm);
}

static uint32_t
rack_get_persists_timer_val(struct tcpcb *tp, struct tcp_rack *rack)
{
        int32_t t;
        int32_t tt;
        uint32_t ret_val;

        t = (tp->t_srtt + (tp->t_rttvar << 2));
        RACK_TCPT_RANGESET(tt, t * tcp_backoff[tp->t_rxtshift],
            rack_persist_min, rack_persist_max, rack->r_ctl.timer_slop);
        rack->r_ctl.rc_hpts_flags |= PACE_TMR_PERSIT;
        ret_val = (uint32_t)tt;
        return (ret_val);
}

static uint32_t
rack_timer_start(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts, int sup_rack)
{
        /*
         * Start the FR timer, we do this based on getting the first one in
         * the rc_tmap. Note that if its NULL we must stop the timer. in all
         * events we need to stop the running timer (if its running) before
         * starting the new one.
         */
        uint32_t thresh, exp, to, srtt, time_since_sent, tstmp_touse;
        uint32_t srtt_cur;
        int32_t idx;
        int32_t is_tlp_timer = 0;
        struct rack_sendmap *rsm;

        if (rack->t_timers_stopped) {
                /* All timers have been stopped none are to run */
                return (0);
        }
        if (rack->rc_in_persist) {
                /* We can't start any timer in persists */
                return (rack_get_persists_timer_val(tp, rack));
        }
        rack->rc_on_min_to = 0;
        if ((tp->t_state < TCPS_ESTABLISHED) ||
            ((tp->t_flags & TF_SACK_PERMIT) == 0)) {
                goto activate_rxt;
        }
        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
        if ((rsm == NULL) || sup_rack) {
                /* Nothing on the send map or no rack */
activate_rxt:
                time_since_sent = 0;
                rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
                if (rsm) {
                        /*
                         * Should we discount the RTX timer any?
                         *
                         * We want to discount it the smallest amount.
                         * If a timer (Rack/TLP or RXT) has gone off more
                         * recently thats the discount we want to use (now - timer time).
                         * If the retransmit of the oldest packet was more recent then
                         * we want to use that (now - oldest-packet-last_transmit_time).
                         *
                         */
                        idx = rsm->r_rtr_cnt - 1;
                        if (TSTMP_GEQ(rack->r_ctl.rc_tlp_rxt_last_time, ((uint32_t)rsm->r_tim_lastsent[idx])))
                                tstmp_touse = (uint32_t)rack->r_ctl.rc_tlp_rxt_last_time;
                        else
                                tstmp_touse = (uint32_t)rsm->r_tim_lastsent[idx];
                        if (TSTMP_GT(cts, tstmp_touse))
                            time_since_sent = cts - tstmp_touse;
                }
                if (SEQ_LT(tp->snd_una, tp->snd_max) ||
                    sbavail(&tptosocket(tp)->so_snd)) {
                        rack->r_ctl.rc_hpts_flags |= PACE_TMR_RXT;
                        to = tp->t_rxtcur;
                        if (to > time_since_sent)
                                to -= time_since_sent;
                        else
                                to = rack->r_ctl.rc_min_to;
                        if (to == 0)
                                to = 1;
                        /* Special case for KEEPINIT */
                        if ((TCPS_HAVEESTABLISHED(tp->t_state) == 0) &&
                            (TP_KEEPINIT(tp) != 0) &&
                            rsm) {
                                /*
                                 * We have to put a ceiling on the rxt timer
                                 * of the keep-init timeout.
                                 */
                                uint32_t max_time, red;

                                max_time = TICKS_2_USEC(TP_KEEPINIT(tp));
                                if (TSTMP_GT(cts, (uint32_t)rsm->r_tim_lastsent[0])) {
                                        red = (cts - (uint32_t)rsm->r_tim_lastsent[0]);
                                        if (red < max_time)
                                                max_time -= red;
                                        else
                                                max_time = 1;
                                }
                                /* Reduce timeout to the keep value if needed */
                                if (max_time < to)
                                        to = max_time;
                        }
                        return (to);
                }
                return (0);
        }
        if (rsm->r_flags & RACK_ACKED) {
                rsm = rack_find_lowest_rsm(rack);
                if (rsm == NULL) {
                        /* No lowest? */
                        goto activate_rxt;
                }
        }
        /* Convert from ms to usecs */
        if ((rsm->r_flags & RACK_SACK_PASSED) ||
            (rsm->r_flags & RACK_RWND_COLLAPSED) ||
            (rsm->r_dupack >= DUP_ACK_THRESHOLD)) {
                if ((tp->t_flags & TF_SENTFIN) &&
                    ((tp->snd_max - tp->snd_una) == 1) &&
                    (rsm->r_flags & RACK_HAS_FIN)) {
                        /*
                         * We don't start a rack timer if all we have is a
                         * FIN outstanding.
                         */
                        goto activate_rxt;
                }
                if ((rack->use_rack_rr == 0) &&
                    (IN_FASTRECOVERY(tp->t_flags)) &&
                    (rack->rack_no_prr == 0) &&
                     (rack->r_ctl.rc_prr_sndcnt  < ctf_fixed_maxseg(tp))) {
                        /*
                         * We are not cheating, in recovery  and
                         * not enough ack's to yet get our next
                         * retransmission out.
                         *
                         * Note that classified attackers do not
                         * get to use the rack-cheat.
                         */
                        goto activate_tlp;
                }
                srtt = rack_grab_rtt(tp, rack);
                thresh = rack_calc_thresh_rack(rack, srtt, cts, __LINE__, 1);
                idx = rsm->r_rtr_cnt - 1;
                exp = ((uint32_t)rsm->r_tim_lastsent[idx]) + thresh;
                if (SEQ_GEQ(exp, cts)) {
                        to = exp - cts;
                        if (to < rack->r_ctl.rc_min_to) {
                                to = rack->r_ctl.rc_min_to;
                                if (rack->r_rr_config == 3)
                                        rack->rc_on_min_to = 1;
                        }
                } else {
                        to = rack->r_ctl.rc_min_to;
                        if (rack->r_rr_config == 3)
                                rack->rc_on_min_to = 1;
                }
        } else {
                /* Ok we need to do a TLP not RACK */
activate_tlp:
                if ((rack->rc_tlp_in_progress != 0) &&
                    (rack->r_ctl.rc_tlp_cnt_out >= rack_tlp_limit)) {
                        /*
                         * The previous send was a TLP and we have sent
                         * N TLP's without sending new data.
                         */
                        goto activate_rxt;
                }
                rsm = TAILQ_LAST_FAST(&rack->r_ctl.rc_tmap, rack_sendmap, r_tnext);
                if (rsm == NULL) {
                        /* We found no rsm to TLP with. */
                        goto activate_rxt;
                }
                if (rsm->r_flags & RACK_HAS_FIN) {
                        /* If its a FIN we dont do TLP */
                        rsm = NULL;
                        goto activate_rxt;
                }
                idx = rsm->r_rtr_cnt - 1;
                time_since_sent = 0;
                if (TSTMP_GEQ(((uint32_t)rsm->r_tim_lastsent[idx]), rack->r_ctl.rc_tlp_rxt_last_time))
                        tstmp_touse = (uint32_t)rsm->r_tim_lastsent[idx];
                else
                        tstmp_touse = (uint32_t)rack->r_ctl.rc_tlp_rxt_last_time;
                if (TSTMP_GT(cts, tstmp_touse))
                    time_since_sent = cts - tstmp_touse;
                is_tlp_timer = 1;
                if (tp->t_srtt) {
                        if ((rack->rc_srtt_measure_made == 0) &&
                            (tp->t_srtt == 1)) {
                                /*
                                 * If another stack as run and set srtt to 1,
                                 * then the srtt was 0, so lets use the initial.
                                 */
                                srtt = RACK_INITIAL_RTO;
                        } else {
                                srtt_cur = tp->t_srtt;
                                srtt = srtt_cur;
                        }
                } else
                        srtt = RACK_INITIAL_RTO;
                /*
                 * If the SRTT is not keeping up and the
                 * rack RTT has spiked we want to use
                 * the last RTT not the smoothed one.
                 */
                if (rack_tlp_use_greater &&
                    tp->t_srtt &&
                    (srtt < rack_grab_rtt(tp, rack))) {
                        srtt = rack_grab_rtt(tp, rack);
                }
                thresh = rack_calc_thresh_tlp(tp, rack, rsm, srtt);
                if (thresh > time_since_sent) {
                        to = thresh - time_since_sent;
                } else {
                        to = rack->r_ctl.rc_min_to;
                        rack_log_alt_to_to_cancel(rack,
                                                  thresh,               /* flex1 */
                                                  time_since_sent,      /* flex2 */
                                                  tstmp_touse,          /* flex3 */
                                                  rack->r_ctl.rc_tlp_rxt_last_time, /* flex4 */
                                                  (uint32_t)rsm->r_tim_lastsent[idx],
                                                  srtt,
                                                  idx, 99);
                }
                if (to < rack_tlp_min) {
                        to = rack_tlp_min;
                }
                if (to > TICKS_2_USEC(tcp_rexmit_max)) {
                        /*
                         * If the TLP time works out to larger than the max
                         * RTO lets not do TLP.. just RTO.
                         */
                        goto activate_rxt;
                }
        }
        if (is_tlp_timer == 0) {
                rack->r_ctl.rc_hpts_flags |= PACE_TMR_RACK;
        } else {
                rack->r_ctl.rc_hpts_flags |= PACE_TMR_TLP;
        }
        if (to == 0)
                to = 1;
        return (to);
}

static void
rack_enter_persist(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts, tcp_seq snd_una)
{
        if (rack->rc_in_persist == 0) {
                if (tp->t_flags & TF_GPUTINPROG) {
                        /*
                         * Stop the goodput now, the calling of the
                         * measurement function clears the flag.
                         */
                        rack_do_goodput_measurement(tp, rack, tp->snd_una, __LINE__,
                                                    RACK_QUALITY_PERSIST);
                }
#ifdef NETFLIX_SHARED_CWND
                if (rack->r_ctl.rc_scw) {
                        tcp_shared_cwnd_idle(rack->r_ctl.rc_scw, rack->r_ctl.rc_scw_index);
                        rack->rack_scwnd_is_idle = 1;
                }
#endif
                rack->r_ctl.rc_went_idle_time = cts;
                if (rack->r_ctl.rc_went_idle_time == 0)
                        rack->r_ctl.rc_went_idle_time = 1;
                if (rack->lt_bw_up) {
                        /* Suspend our LT BW measurement */
                        uint64_t tmark;

                        rack->r_ctl.lt_bw_bytes += (snd_una - rack->r_ctl.lt_seq);
                        rack->r_ctl.lt_seq = snd_una;
                        tmark = tcp_tv_to_lusec(&rack->r_ctl.act_rcv_time);
                        if (tmark >= rack->r_ctl.lt_timemark) {
                                rack->r_ctl.lt_bw_time += (tmark - rack->r_ctl.lt_timemark);
                        }
                        rack->r_ctl.lt_timemark = tmark;
                        rack->lt_bw_up = 0;
                        rack->r_persist_lt_bw_off = 1;
                }
                rack_timer_cancel(tp, rack, cts, __LINE__);
                rack->r_ctl.persist_lost_ends = 0;
                rack->probe_not_answered = 0;
                rack->forced_ack = 0;
                tp->t_rxtshift = 0;
                RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                              rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
                rack->rc_in_persist = 1;
        }
}

static void
rack_exit_persist(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts)
{
        if (tcp_in_hpts(rack->rc_tp)) {
                tcp_hpts_remove(rack->rc_tp);
                rack->r_ctl.rc_hpts_flags = 0;
        }
#ifdef NETFLIX_SHARED_CWND
        if (rack->r_ctl.rc_scw) {
                tcp_shared_cwnd_active(rack->r_ctl.rc_scw, rack->r_ctl.rc_scw_index);
                rack->rack_scwnd_is_idle = 0;
        }
#endif
        if (rack->rc_gp_dyn_mul &&
            (rack->use_fixed_rate == 0) &&
            (rack->rc_always_pace)) {
                /*
                 * Do we count this as if a probe-rtt just
                 * finished?
                 */
                uint32_t time_idle, idle_min;

                time_idle = cts - rack->r_ctl.rc_went_idle_time;
                idle_min = rack_min_probertt_hold;
                if (rack_probertt_gpsrtt_cnt_div) {
                        uint64_t extra;
                        extra = (uint64_t)rack->r_ctl.rc_gp_srtt *
                                (uint64_t)rack_probertt_gpsrtt_cnt_mul;
                        extra /= (uint64_t)rack_probertt_gpsrtt_cnt_div;
                        idle_min += (uint32_t)extra;
                }
                if (time_idle >= idle_min) {
                        /* Yes, we count it as a probe-rtt. */
                        uint32_t us_cts;

                        us_cts = tcp_get_usecs(NULL);
                        if (rack->in_probe_rtt == 0) {
                                rack->r_ctl.rc_lower_rtt_us_cts = us_cts;
                                rack->r_ctl.rc_time_probertt_entered = rack->r_ctl.rc_lower_rtt_us_cts;
                                rack->r_ctl.rc_time_probertt_starts = rack->r_ctl.rc_lower_rtt_us_cts;
                                rack->r_ctl.rc_time_of_last_probertt = rack->r_ctl.rc_lower_rtt_us_cts;
                        } else {
                                rack_exit_probertt(rack, us_cts);
                        }
                }
        }
        if (rack->r_persist_lt_bw_off) {
                /* Continue where we left off */
                rack->r_ctl.lt_timemark = tcp_get_u64_usecs(NULL);
                rack->lt_bw_up = 1;
                rack->r_persist_lt_bw_off = 0;
        }
        rack->rc_in_persist = 0;
        rack->r_ctl.rc_went_idle_time = 0;
        tp->t_rxtshift = 0;
        RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
           rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
        rack->r_ctl.rc_agg_delayed = 0;
        rack->r_early = 0;
        rack->r_late = 0;
        rack->r_ctl.rc_agg_early = 0;
}

static void
rack_log_hpts_diag(struct tcp_rack *rack, uint32_t cts,
                   struct hpts_diag *diag, struct timeval *tv)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = diag->p_nxt_slot;
                log.u_bbr.flex2 = diag->p_cur_slot;
                log.u_bbr.flex3 = diag->slot_req;
                log.u_bbr.flex4 = diag->inp_hptsslot;
                log.u_bbr.flex5 = diag->time_remaining;
                log.u_bbr.flex6 = diag->need_new_to;
                log.u_bbr.flex7 = diag->p_hpts_active;
                log.u_bbr.flex8 = diag->p_on_min_sleep;
                /* Hijack other fields as needed */
                log.u_bbr.epoch = diag->have_slept;
                log.u_bbr.lt_epoch = diag->yet_to_sleep;
                log.u_bbr.pkts_out = diag->co_ret;
                log.u_bbr.applimited = diag->hpts_sleep_time;
                log.u_bbr.delivered = diag->p_prev_slot;
                log.u_bbr.inflight = diag->p_runningslot;
                log.u_bbr.bw_inuse = diag->wheel_slot;
                log.u_bbr.rttProp = diag->wheel_cts;
                log.u_bbr.timeStamp = cts;
                log.u_bbr.delRate = diag->maxslots;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_HPTSDIAG, 0,
                    0, &log, false, tv);
        }

}

static void
rack_log_wakeup(struct tcpcb *tp, struct tcp_rack *rack, struct sockbuf *sb, uint32_t len, int type)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = sb->sb_flags;
                log.u_bbr.flex2 = len;
                log.u_bbr.flex3 = sb->sb_state;
                log.u_bbr.flex8 = type;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_LOG_SB_WAKE, 0,
                    len, &log, false, &tv);
        }
}

static void
rack_start_hpts_timer (struct tcp_rack *rack, struct tcpcb *tp, uint32_t cts,
      int32_t usecs, uint32_t tot_len_this_send, int sup_rack)
{
        struct hpts_diag diag;
        struct inpcb *inp = tptoinpcb(tp);
        struct timeval tv;
        uint32_t delayed_ack = 0;
        uint32_t hpts_timeout;
        uint32_t entry_usecs = usecs;
        uint8_t stopped;
        uint32_t left = 0;
        uint32_t us_cts;

        if ((tp->t_state == TCPS_CLOSED) ||
            (tp->t_state == TCPS_LISTEN)) {
                return;
        }
        if (tcp_in_hpts(tp)) {
                /* Already on the pacer */
                return;
        }
        stopped = rack->rc_tmr_stopped;
        if (stopped && TSTMP_GT(rack->r_ctl.rc_timer_exp, cts)) {
                left = rack->r_ctl.rc_timer_exp - cts;
        }
        rack->r_ctl.rc_timer_exp = 0;
        rack->r_ctl.rc_hpts_flags = 0;
        us_cts = tcp_get_usecs(&tv);
        /* Now early/late accounting */
        rack_log_pacing_delay_calc(rack, entry_usecs, usecs, 0, 0, 0, 26, __LINE__, NULL, 0);
        if (rack->r_early && (rack->rc_ack_can_sendout_data == 0)) {
                /*
                 * We have a early carry over set,
                 * we can always add more time so we
                 * can always make this compensation.
                 *
                 * Note if ack's are allowed to wake us do not
                 * penalize the next timer for being awoke
                 * by an ack aka the rc_agg_early (non-paced mode).
                 */
                usecs += rack->r_ctl.rc_agg_early;
                rack->r_early = 0;
                rack->r_ctl.rc_agg_early = 0;
        }
        if ((rack->r_late) &&
            ((rack->r_use_hpts_min == 0) || (rack->dgp_on == 0))) {
                /*
                 * This is harder, we can
                 * compensate some but it
                 * really depends on what
                 * the current pacing time is.
                 */
                if (rack->r_ctl.rc_agg_delayed >= usecs) {
                        /*
                         * We can't compensate for it all.
                         * And we have to have some time
                         * on the clock. We always have a min
                         * 10 HPTS timer units (10 x 10 i.e. 100 usecs).
                         */
                        if (usecs <= HPTS_USECS_PER_SLOT) {
                                /* We gain delay */
                                rack->r_ctl.rc_agg_delayed += (HPTS_USECS_PER_SLOT - usecs);
                                usecs = HPTS_USECS_PER_SLOT;
                        } else {
                                /* We take off some */
                                rack->r_ctl.rc_agg_delayed -= (usecs - HPTS_USECS_PER_SLOT);
                                usecs = HPTS_USECS_PER_SLOT;
                        }
                } else {
                        usecs -= rack->r_ctl.rc_agg_delayed;
                        rack->r_ctl.rc_agg_delayed = 0;
                        /* Make sure we have 100 useconds at minimum */
                        if (usecs < HPTS_USECS_PER_SLOT) {
                                rack->r_ctl.rc_agg_delayed = HPTS_USECS_PER_SLOT - usecs;
                                usecs = HPTS_USECS_PER_SLOT;
                        }
                        if (rack->r_ctl.rc_agg_delayed == 0)
                                rack->r_late = 0;
                }
        } else if (rack->r_late) {
                /* r_use_hpts_min is on and so is DGP */
                uint32_t max_red;

                max_red = (usecs * rack->r_ctl.max_reduction) / 100;
                if (max_red >= rack->r_ctl.rc_agg_delayed) {
                        usecs -= rack->r_ctl.rc_agg_delayed;
                        rack->r_ctl.rc_agg_delayed = 0;
                } else {
                        usecs -= max_red;
                        rack->r_ctl.rc_agg_delayed -= max_red;
                }
        }
        if ((rack->r_use_hpts_min == 1) &&
            (usecs > 0) &&
            (rack->dgp_on == 1)) {
                /*
                 * We are enforcing a min pacing timer
                 * based on our hpts min timeout.
                 */
                uint32_t min;

                min = get_hpts_min_sleep_time();
                if (min > usecs) {
                        usecs = min;
                }
        }
        hpts_timeout = rack_timer_start(tp, rack, cts, sup_rack);
        if (tp->t_flags & TF_DELACK) {
                delayed_ack = TICKS_2_USEC(tcp_delacktime);
                rack->r_ctl.rc_hpts_flags |= PACE_TMR_DELACK;
        }
        if (delayed_ack && ((hpts_timeout == 0) ||
                            (delayed_ack < hpts_timeout)))
                hpts_timeout = delayed_ack;
        else
                rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_DELACK;
        /*
         * If no timers are going to run and we will fall off the hptsi
         * wheel, we resort to a keep-alive timer if its configured.
         */
        if ((hpts_timeout == 0) &&
            (usecs == 0)) {
                if ((V_tcp_always_keepalive || inp->inp_socket->so_options & SO_KEEPALIVE) &&
                    (tp->t_state <= TCPS_CLOSING)) {
                        /*
                         * Ok we have no timer (persists, rack, tlp, rxt  or
                         * del-ack), we don't have segments being paced. So
                         * all that is left is the keepalive timer.
                         */
                        if (TCPS_HAVEESTABLISHED(tp->t_state)) {
                                /* Get the established keep-alive time */
                                hpts_timeout = TICKS_2_USEC(TP_KEEPIDLE(tp));
                        } else {
                                /*
                                 * Get the initial setup keep-alive time,
                                 * note that this is probably not going to
                                 * happen, since rack will be running a rxt timer
                                 * if a SYN of some sort is outstanding. It is
                                 * actually handled in rack_timeout_rxt().
                                 */
                                hpts_timeout = TICKS_2_USEC(TP_KEEPINIT(tp));
                        }
                        rack->r_ctl.rc_hpts_flags |= PACE_TMR_KEEP;
                        if (rack->in_probe_rtt) {
                                /*
                                 * We want to instead not wake up a long time from
                                 * now but to wake up about the time we would
                                 * exit probe-rtt and initiate a keep-alive ack.
                                 * This will get us out of probe-rtt and update
                                 * our min-rtt.
                                 */
                                hpts_timeout = rack_min_probertt_hold;
                        }
                }
        }
        if (left && (stopped & (PACE_TMR_KEEP | PACE_TMR_DELACK)) ==
            (rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK)) {
                /*
                 * RACK, TLP, persists and RXT timers all are restartable
                 * based on actions input .. i.e we received a packet (ack
                 * or sack) and that changes things (rw, or snd_una etc).
                 * Thus we can restart them with a new value. For
                 * keep-alive, delayed_ack we keep track of what was left
                 * and restart the timer with a smaller value.
                 */
                if (left < hpts_timeout)
                        hpts_timeout = left;
        }
        if (hpts_timeout) {
                /*
                 * Hack alert for now we can't time-out over 2,147,483
                 * seconds (a bit more than 596 hours), which is probably ok
                 * :).
                 */
                if (hpts_timeout > 0x7ffffffe)
                        hpts_timeout = 0x7ffffffe;
                rack->r_ctl.rc_timer_exp = cts + hpts_timeout;
        }
        rack_log_pacing_delay_calc(rack, entry_usecs, usecs, hpts_timeout, 0, 0, 27, __LINE__, NULL, 0);
        if ((rack->gp_ready == 0) &&
            (rack->use_fixed_rate == 0) &&
            (hpts_timeout < usecs) &&
            (rack->r_ctl.rc_hpts_flags & (PACE_TMR_TLP|PACE_TMR_RXT))) {
                /*
                 * We have no good estimate yet for the
                 * old clunky burst mitigation or the
                 * real pacing. And the tlp or rxt is smaller
                 * than the pacing calculation. Lets not
                 * pace that long since we know the calculation
                 * so far is not accurate.
                 */
                usecs = hpts_timeout;
        }
        /**
         * Turn off all the flags for queuing by default. The
         * flags have important meanings to what happens when
         * LRO interacts with the transport. Most likely (by default now)
         * mbuf_queueing and ack compression are on. So the transport
         * has a couple of flags that control what happens (if those
         * are not on then these flags won't have any effect since it
         * won't go through the queuing LRO path).
         *
         * TF2_MBUF_QUEUE_READY - This flags says that I am busy
         *                        pacing output, so don't disturb. But
         *                        it also means LRO can wake me if there
         *                        is a SACK arrival.
         *
         * TF2_DONT_SACK_QUEUE - This flag is used in conjunction
         *                       with the above flag (QUEUE_READY) and
         *                       when present it says don't even wake me
         *                       if a SACK arrives.
         *
         * The idea behind these flags is that if we are pacing we
         * set the MBUF_QUEUE_READY and only get woken up if
         * a SACK arrives (which could change things) or if
         * our pacing timer expires. If, however, we have a rack
         * timer running, then we don't even want a sack to wake
         * us since the rack timer has to expire before we can send.
         *
         * Other cases should usually have none of the flags set
         * so LRO can call into us.
         */
        tp->t_flags2 &= ~(TF2_DONT_SACK_QUEUE|TF2_MBUF_QUEUE_READY);
        if (usecs) {
                rack->r_ctl.rc_hpts_flags |= PACE_PKT_OUTPUT;
                rack->r_ctl.rc_last_output_to = us_cts + usecs;
                /*
                 * A pacing timer (usecs microseconds) is being set, in
                 * such a case we cannot send (we are blocked by
                 * the timer). So lets tell LRO that it should not
                 * wake us unless there is a SACK. Note this only
                 * will be effective if mbuf queueing is on or
                 * compressed acks are being processed.
                 */
                tp->t_flags2 |= TF2_MBUF_QUEUE_READY;
                /*
                 * But wait if we have a Rack timer running
                 * even a SACK should not disturb us (with
                 * the exception of r_rr_config 3).
                 */
                if ((rack->r_ctl.rc_hpts_flags & PACE_TMR_RACK) ||
                    (IN_RECOVERY(tp->t_flags))) {
                        if (rack->r_rr_config != 3)
                                tp->t_flags2 |= TF2_DONT_SACK_QUEUE;
                        else if (rack->rc_pace_dnd) {
                                /*
                                 * When DND is on, we only let a sack
                                 * interrupt us if we are not in recovery.
                                 *
                                 * If DND is off, then we never hit here
                                 * and let all sacks wake us up.
                                 *
                                 */
                                tp->t_flags2 |= TF2_DONT_SACK_QUEUE;
                        }
                }
                if (rack->rc_ack_can_sendout_data) {
                        /*
                         * Ahh but wait, this is that special case
                         * where the pacing timer can be disturbed
                         * backout the changes (used for non-paced
                         * burst limiting).
                         */
                        tp->t_flags2 &= ~(TF2_DONT_SACK_QUEUE |
                            TF2_MBUF_QUEUE_READY);
                }
                if ((rack->use_rack_rr) &&
                    (rack->r_rr_config < 2) &&
                    ((hpts_timeout) && (hpts_timeout < usecs))) {
                        /*
                         * Arrange for the hpts to kick back in after the
                         * t-o if the t-o does not cause a send.
                         */
                        tcp_hpts_insert(tp, hpts_timeout, &diag);
                        rack_log_hpts_diag(rack, us_cts, &diag, &tv);
                        rack_log_to_start(rack, cts, hpts_timeout, usecs, 0);
                } else {
                        tcp_hpts_insert(tp, usecs, &diag);
                        rack_log_hpts_diag(rack, us_cts, &diag, &tv);
                        rack_log_to_start(rack, cts, hpts_timeout, usecs, 1);
                }
        } else if (hpts_timeout) {
                /*
                 * With respect to t_flags2(?) here, lets let any new acks wake
                 * us up here. Since we are not pacing (no pacing timer), output
                 * can happen so we should let it. If its a Rack timer, then any inbound
                 * packet probably won't change the sending (we will be blocked)
                 * but it may change the prr stats so letting it in (the set defaults
                 * at the start of this block) are good enough.
                 */
                rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
                tcp_hpts_insert(tp, hpts_timeout, &diag);
                rack_log_hpts_diag(rack, us_cts, &diag, &tv);
                rack_log_to_start(rack, cts, hpts_timeout, usecs, 0);
        } else {
                /* No timer starting */
#ifdef INVARIANTS
                if (SEQ_GT(tp->snd_max, tp->snd_una)) {
                        panic("tp:%p rack:%p tlts:%d cts:%u usecs:%u pto:%u -- no timer started?",
                            tp, rack, tot_len_this_send, cts, usecs, hpts_timeout);
                }
#endif
        }
        rack->rc_tmr_stopped = 0;
        if (usecs)
                rack_log_type_bbrsnd(rack, tot_len_this_send, usecs, us_cts, &tv, __LINE__);
}

static void
rack_mark_lost(struct tcpcb *tp,
    struct tcp_rack *rack, struct rack_sendmap *rsm, uint32_t cts)
{
        struct rack_sendmap *nrsm;
        uint32_t thresh,  exp;

        thresh = rack_calc_thresh_rack(rack, rack_grab_rtt(tp, rack), cts, __LINE__, 0);
        nrsm = rsm;
        TAILQ_FOREACH_FROM(nrsm, &rack->r_ctl.rc_tmap, r_tnext) {
                if ((nrsm->r_flags & RACK_SACK_PASSED) == 0) {
                        /* Got up to all that were marked sack-passed */
                        break;
                }
                if ((nrsm->r_flags & RACK_WAS_LOST) == 0) {
                        exp = ((uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)]) + thresh;
                        if (TSTMP_LT(exp, cts) || (exp == cts)) {
                                /* We now consider it lost */
                                nrsm->r_flags |= RACK_WAS_LOST;
                                rack->r_ctl.rc_considered_lost += nrsm->r_end - nrsm->r_start;
                        } else {
                                /* Past here it won't be lost so stop */
                                break;
                        }
                }
        }
}

static inline void
rack_mark_nolonger_lost(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
        KASSERT((rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start)),
                ("rsm:%p rack:%p rc_considered_lost goes negative", rsm,  rack));
        rsm->r_flags &= ~RACK_WAS_LOST;
        if (rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start))
                rack->r_ctl.rc_considered_lost -= rsm->r_end - rsm->r_start;
        else
                rack->r_ctl.rc_considered_lost = 0;
}

/*
 * RACK Timer, here we simply do logging and house keeping.
 * the normal rack_output() function will call the
 * appropriate thing to check if we need to do a RACK retransmit.
 * We return 1, saying don't proceed with rack_output only
 * when all timers have been stopped (destroyed PCB?).
 */
static int
rack_timeout_rack(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts)
{
        /*
         * This timer simply provides an internal trigger to send out data.
         * The check_recovery_mode call will see if there are needed
         * retransmissions, if so we will enter fast-recovery. The output
         * call may or may not do the same thing depending on sysctl
         * settings.
         */
        struct rack_sendmap *rsm;

        counter_u64_add(rack_to_tot, 1);
        if (rack->r_state && (rack->r_state != tp->t_state))
                rack_set_state(tp, rack);
        rack->rc_on_min_to = 0;
        rsm = rack_check_recovery_mode(tp, cts);
        rack_log_to_event(rack, RACK_TO_FRM_RACK, rsm);
        if (rsm) {
                /* We need to stroke any lost that are now declared as lost */
                rack_mark_lost(tp, rack, rsm, cts);
                rack->r_ctl.rc_resend = rsm;
                rack->r_timer_override = 1;
                if (rack->use_rack_rr) {
                        /*
                         * Don't accumulate extra pacing delay
                         * we are allowing the rack timer to
                         * over-ride pacing i.e. rrr takes precedence
                         * if the pacing interval is longer than the rrr
                         * time (in other words we get the min pacing
                         * time versus rrr pacing time).
                         */
                        rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
                }
        }
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_RACK;
        if (rsm == NULL) {
                /* restart a timer and return 1 */
                rack_start_hpts_timer(rack, tp, cts,
                                      0, 0, 0);
                return (1);
        }
        return (0);
}



static void
rack_adjust_orig_mlen(struct rack_sendmap *rsm)
{

        if ((M_TRAILINGROOM(rsm->m) != rsm->orig_t_space)) {
                /*
                 * The trailing space changed, mbufs can grow
                 * at the tail but they can't shrink from
                 * it, KASSERT that. Adjust the orig_m_len to
                 * compensate for this change.
                 */
                KASSERT((rsm->orig_t_space > M_TRAILINGROOM(rsm->m)),
                        ("mbuf:%p rsm:%p trailing_space:%jd ots:%u oml:%u mlen:%u\n",
                         rsm->m,
                         rsm,
                         (intmax_t)M_TRAILINGROOM(rsm->m),
                         rsm->orig_t_space,
                         rsm->orig_m_len,
                         rsm->m->m_len));
                rsm->orig_m_len += (rsm->orig_t_space - M_TRAILINGROOM(rsm->m));
                rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
        }
        if (rsm->m->m_len < rsm->orig_m_len) {
                /*
                 * Mbuf shrank, trimmed off the top by an ack, our
                 * offset changes.
                 */
                KASSERT((rsm->soff >= (rsm->orig_m_len - rsm->m->m_len)),
                        ("mbuf:%p len:%u rsm:%p oml:%u soff:%u\n",
                         rsm->m, rsm->m->m_len,
                         rsm, rsm->orig_m_len,
                         rsm->soff));
                if (rsm->soff >= (rsm->orig_m_len - rsm->m->m_len))
                        rsm->soff -= (rsm->orig_m_len - rsm->m->m_len);
                else
                        rsm->soff = 0;
                rsm->orig_m_len = rsm->m->m_len;
#ifdef INVARIANTS
        } else if (rsm->m->m_len > rsm->orig_m_len) {
                panic("rsm:%p m:%p m_len grew outside of t_space compensation",
                      rsm, rsm->m);
#endif
        }
}

static void
rack_setup_offset_for_rsm(struct tcp_rack *rack, struct rack_sendmap *src_rsm, struct rack_sendmap *rsm)
{
        struct mbuf *m;
        uint32_t soff;

        if (src_rsm->m &&
            ((src_rsm->orig_m_len != src_rsm->m->m_len) ||
             (M_TRAILINGROOM(src_rsm->m) != src_rsm->orig_t_space))) {
                /* Fix up the orig_m_len and possibly the mbuf offset */
                rack_adjust_orig_mlen(src_rsm);
        }
        m = src_rsm->m;
        soff = src_rsm->soff + (src_rsm->r_end - src_rsm->r_start);
        while (soff >= m->m_len) {
                /* Move out past this mbuf */
                soff -= m->m_len;
                m = m->m_next;
                KASSERT((m != NULL),
                        ("rsm:%p nrsm:%p hit at soff:%u null m",
                         src_rsm, rsm, soff));
                if (m == NULL) {
                        /* This should *not* happen which is why there is a kassert */
                        src_rsm->m = sbsndmbuf(&rack->rc_inp->inp_socket->so_snd,
                                               (src_rsm->r_start - rack->rc_tp->snd_una),
                                               &src_rsm->soff);
                        src_rsm->orig_m_len = src_rsm->m->m_len;
                        src_rsm->orig_t_space = M_TRAILINGROOM(src_rsm->m);
                        rsm->m = sbsndmbuf(&rack->rc_inp->inp_socket->so_snd,
                                           (rsm->r_start - rack->rc_tp->snd_una),
                                           &rsm->soff);
                        rsm->orig_m_len = rsm->m->m_len;
                        rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                        return;
                }
        }
        rsm->m = m;
        rsm->soff = soff;
        rsm->orig_m_len = m->m_len;
        rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
}

static inline void
rack_clone_rsm(struct tcp_rack *rack, struct rack_sendmap *nrsm,
               struct rack_sendmap *rsm, uint32_t start)
{
        int idx;

        nrsm->r_start = start;
        nrsm->r_end = rsm->r_end;
        nrsm->r_rtr_cnt = rsm->r_rtr_cnt;
        nrsm->r_act_rxt_cnt = rsm->r_act_rxt_cnt;
        nrsm->r_flags = rsm->r_flags;
        nrsm->r_dupack = rsm->r_dupack;
        nrsm->r_no_rtt_allowed = rsm->r_no_rtt_allowed;
        nrsm->r_rtr_bytes = 0;
        nrsm->r_fas = rsm->r_fas;
        nrsm->r_bas = rsm->r_bas;
        tqhash_update_end(rack->r_ctl.tqh, rsm, nrsm->r_start);
        nrsm->r_just_ret = rsm->r_just_ret;
        for (idx = 0; idx < nrsm->r_rtr_cnt; idx++) {
                nrsm->r_tim_lastsent[idx] = rsm->r_tim_lastsent[idx];
        }
        /* Now if we have SYN flag we keep it on the left edge */
        if (nrsm->r_flags & RACK_HAS_SYN)
                nrsm->r_flags &= ~RACK_HAS_SYN;
        /* Now if we have a FIN flag we keep it on the right edge */
        if (rsm->r_flags & RACK_HAS_FIN)
                rsm->r_flags &= ~RACK_HAS_FIN;
        /* Push bit must go to the right edge as well */
        if (rsm->r_flags & RACK_HAD_PUSH)
                rsm->r_flags &= ~RACK_HAD_PUSH;
        /* Update the count if app limited */
        if (nrsm->r_flags & RACK_APP_LIMITED)
                rack->r_ctl.rc_app_limited_cnt++;
        /* Clone over the state of the hw_tls flag */
        nrsm->r_hw_tls = rsm->r_hw_tls;
        /*
         * Now we need to find nrsm's new location in the mbuf chain
         * we basically calculate a new offset, which is soff +
         * how much is left in original rsm. Then we walk out the mbuf
         * chain to find the righ position, it may be the same mbuf
         * or maybe not.
         */
        KASSERT(((rsm->m != NULL) ||
                 (rsm->r_flags & (RACK_HAS_SYN|RACK_HAS_FIN))),
                ("rsm:%p nrsm:%p rack:%p -- rsm->m is NULL?", rsm, nrsm, rack));
        if (rsm->m)
                rack_setup_offset_for_rsm(rack, rsm, nrsm);
}

static struct rack_sendmap *
rack_merge_rsm(struct tcp_rack *rack,
               struct rack_sendmap *l_rsm,
               struct rack_sendmap *r_rsm)
{
        /*
         * We are merging two ack'd RSM's,
         * the l_rsm is on the left (lower seq
         * values) and the r_rsm is on the right
         * (higher seq value). The simplest way
         * to merge these is to move the right
         * one into the left. I don't think there
         * is any reason we need to try to find
         * the oldest (or last oldest retransmitted).
         */
        rack_log_map_chg(rack->rc_tp, rack, NULL,
                         l_rsm, r_rsm, MAP_MERGE, r_rsm->r_end, __LINE__);
        tqhash_update_end(rack->r_ctl.tqh, l_rsm, r_rsm->r_end);
        if (l_rsm->r_dupack < r_rsm->r_dupack)
                l_rsm->r_dupack = r_rsm->r_dupack;
        if (r_rsm->r_rtr_bytes)
                l_rsm->r_rtr_bytes += r_rsm->r_rtr_bytes;
        if (r_rsm->r_in_tmap) {
                /* This really should not happen */
                TAILQ_REMOVE(&rack->r_ctl.rc_tmap, r_rsm, r_tnext);
                r_rsm->r_in_tmap = 0;
        }

        /* Now the flags */
        if (r_rsm->r_flags & RACK_HAS_FIN)
                l_rsm->r_flags |= RACK_HAS_FIN;
        if (r_rsm->r_flags & RACK_TLP)
                l_rsm->r_flags |= RACK_TLP;
        if (r_rsm->r_flags & RACK_RWND_COLLAPSED)
                l_rsm->r_flags |= RACK_RWND_COLLAPSED;
        if ((r_rsm->r_flags & RACK_APP_LIMITED) &&
            ((l_rsm->r_flags & RACK_APP_LIMITED) == 0)) {
                /*
                 * If both are app-limited then let the
                 * free lower the count. If right is app
                 * limited and left is not, transfer.
                 */
                l_rsm->r_flags |= RACK_APP_LIMITED;
                r_rsm->r_flags &= ~RACK_APP_LIMITED;
                if (r_rsm == rack->r_ctl.rc_first_appl)
                        rack->r_ctl.rc_first_appl = l_rsm;
        }
        tqhash_remove(rack->r_ctl.tqh, r_rsm, REMOVE_TYPE_MERGE);
        /*
         * We keep the largest value, which is the newest
         * send. We do this in case a segment that is
         * joined together and not part of a GP estimate
         * later gets expanded into the GP estimate.
         *
         * We prohibit the merging of unlike kinds i.e.
         * all pieces that are in the GP estimate can be
         * merged and all pieces that are not in a GP estimate
         * can be merged, but not disimilar pieces. Combine
         * this with taking the highest here and we should
         * be ok unless of course the client reneges. Then
         * all bets are off.
         */
        if(l_rsm->r_tim_lastsent[(l_rsm->r_rtr_cnt-1)] <
           r_rsm->r_tim_lastsent[(r_rsm->r_rtr_cnt-1)]) {
                l_rsm->r_tim_lastsent[(l_rsm->r_rtr_cnt-1)] = r_rsm->r_tim_lastsent[(r_rsm->r_rtr_cnt-1)];
        }
        /*
         * When merging two RSM's we also need to consider the ack time and keep
         * newest. If the ack gets merged into a measurement then that is the
         * one we will want to be using.
         */
        if(l_rsm->r_ack_arrival  < r_rsm->r_ack_arrival)
                l_rsm->r_ack_arrival = r_rsm->r_ack_arrival;

        if ((r_rsm->r_limit_type == 0) && (l_rsm->r_limit_type != 0)) {
                /* Transfer the split limit to the map we free */
                r_rsm->r_limit_type = l_rsm->r_limit_type;
                l_rsm->r_limit_type = 0;
        }
        rack_free(rack, r_rsm);
        l_rsm->r_flags |= RACK_MERGED;
        return (l_rsm);
}

/*
 * TLP Timer, here we simply setup what segment we want to
 * have the TLP expire on, the normal rack_output() will then
 * send it out.
 *
 * We return 1, saying don't proceed with rack_output only
 * when all timers have been stopped (destroyed PCB?).
 */
static int
rack_timeout_tlp(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts, uint8_t *doing_tlp)
{
        /*
         * Tail Loss Probe.
         */
        struct rack_sendmap *rsm = NULL;
        int insret __diagused;
        struct socket *so = tptosocket(tp);
        uint32_t amm;
        uint32_t out, avail;
        int collapsed_win = 0;

        if (TSTMP_LT(cts, rack->r_ctl.rc_timer_exp)) {
                /* Its not time yet */
                return (0);
        }
        if (ctf_progress_timeout_check(tp, true)) {
                rack_log_progress_event(rack, tp, tick, PROGRESS_DROP, __LINE__);
                return (-ETIMEDOUT);    /* tcp_drop() */
        }
        /*
         * A TLP timer has expired. We have been idle for 2 rtts. So we now
         * need to figure out how to force a full MSS segment out.
         */
        rack_log_to_event(rack, RACK_TO_FRM_TLP, NULL);
        rack->r_ctl.retran_during_recovery = 0;
        rack->r_might_revert = 0;
        rack->r_ctl.dsack_byte_cnt = 0;
        counter_u64_add(rack_tlp_tot, 1);
        if (rack->r_state && (rack->r_state != tp->t_state))
                rack_set_state(tp, rack);
        avail = sbavail(&so->so_snd);
        out = tp->snd_max - tp->snd_una;
        if ((out > tp->snd_wnd) || rack->rc_has_collapsed) {
                /* special case, we need a retransmission */
                collapsed_win = 1;
                goto need_retran;
        }
        if (rack->r_ctl.dsack_persist && (rack->r_ctl.rc_tlp_cnt_out >= 1)) {
                rack->r_ctl.dsack_persist--;
                if (rack->r_ctl.num_dsack && (rack->r_ctl.dsack_persist == 0)) {
                        rack->r_ctl.num_dsack = 0;
                }
                rack_log_dsack_event(rack, 1, __LINE__, 0, 0);
        }
        if ((tp->t_flags & TF_GPUTINPROG) &&
            (rack->r_ctl.rc_tlp_cnt_out == 1)) {
                /*
                 * If this is the second in a row
                 * TLP and we are doing a measurement
                 * its time to abandon the measurement.
                 * Something is likely broken on
                 * the clients network and measuring a
                 * broken network does us no good.
                 */
                tp->t_flags &= ~TF_GPUTINPROG;
                rack_log_pacing_delay_calc(rack, (tp->gput_ack - tp->gput_seq) /*flex2*/,
                                           rack->r_ctl.rc_gp_srtt /*flex1*/,
                                           tp->gput_seq,
                                           0, 0, 18, __LINE__, NULL, 0);
        }
        /*
         * Check our send oldest always settings, and if
         * there is an oldest to send jump to the need_retran.
         */
        if (rack_always_send_oldest && (TAILQ_EMPTY(&rack->r_ctl.rc_tmap) == 0))
                goto need_retran;

        if (avail > out) {
                /* New data is available */
                amm = avail - out;
                if (amm > ctf_fixed_maxseg(tp)) {
                        amm = ctf_fixed_maxseg(tp);
                        if ((amm + out) > tp->snd_wnd) {
                                /* We are rwnd limited */
                                goto need_retran;
                        }
                } else if (amm < ctf_fixed_maxseg(tp)) {
                        /* not enough to fill a MTU */
                        goto need_retran;
                }
                if (IN_FASTRECOVERY(tp->t_flags)) {
                        /* Unlikely */
                        if (rack->rack_no_prr == 0) {
                                if (out + amm <= tp->snd_wnd) {
                                        rack->r_ctl.rc_prr_sndcnt = amm;
                                        rack->r_ctl.rc_tlp_new_data = amm;
                                        rack_log_to_prr(rack, 4, 0, __LINE__);
                                }
                        } else
                                goto need_retran;
                } else {
                        /* Set the send-new override */
                        if (out + amm <= tp->snd_wnd)
                                rack->r_ctl.rc_tlp_new_data = amm;
                        else
                                goto need_retran;
                }
                rack->r_ctl.rc_tlpsend = NULL;
                counter_u64_add(rack_tlp_newdata, 1);
                goto send;
        }
need_retran:
        /*
         * Ok we need to arrange the last un-acked segment to be re-sent, or
         * optionally the first un-acked segment.
         */
        if (collapsed_win == 0) {
                if (rack_always_send_oldest)
                        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
                else {
                        rsm = tqhash_max(rack->r_ctl.tqh);
                        if (rsm && (rsm->r_flags & (RACK_ACKED | RACK_HAS_FIN))) {
                                rsm = rack_find_high_nonack(rack, rsm);
                        }
                }
                if (rsm == NULL) {
#ifdef TCP_BLACKBOX
                        tcp_log_dump_tp_logbuf(tp, "nada counter trips", M_NOWAIT, true);
#endif
                        goto out;
                }
        } else {
                /*
                 * We had a collapsed window, lets find
                 * the point before the collapse.
                 */
                if (SEQ_GT((rack->r_ctl.last_collapse_point - 1), rack->rc_tp->snd_una))
                        rsm = tqhash_find(rack->r_ctl.tqh, (rack->r_ctl.last_collapse_point - 1));
                else {
                        rsm = tqhash_min(rack->r_ctl.tqh);
                }
                if (rsm == NULL) {
                        /* Huh */
                        goto out;
                }
        }
        if ((rsm->r_end - rsm->r_start) > ctf_fixed_maxseg(tp)) {
                /*
                 * We need to split this the last segment in two.
                 */
                struct rack_sendmap *nrsm;

                nrsm = rack_alloc_full_limit(rack);
                if (nrsm == NULL) {
                        /*
                         * No memory to split, we will just exit and punt
                         * off to the RXT timer.
                         */
                        goto out;
                }
                rack_clone_rsm(rack, nrsm, rsm,
                               (rsm->r_end - ctf_fixed_maxseg(tp)));
                rack_log_map_chg(tp, rack, NULL, rsm, nrsm, MAP_SPLIT, 0, __LINE__);
#ifndef INVARIANTS
                (void)tqhash_insert(rack->r_ctl.tqh, nrsm);
#else
                if ((insret = tqhash_insert(rack->r_ctl.tqh, nrsm)) != 0) {
                        panic("Insert in tailq_hash of %p fails ret:%d rack:%p rsm:%p",
                              nrsm, insret, rack, rsm);
                }
#endif
                if (rsm->r_in_tmap) {
                        TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, rsm, nrsm, r_tnext);
                        nrsm->r_in_tmap = 1;
                }
                rsm = nrsm;
        }
        rack->r_ctl.rc_tlpsend = rsm;
send:
        /* Make sure output path knows we are doing a TLP */
        *doing_tlp = 1;
        rack->r_timer_override = 1;
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_TLP;
        return (0);
out:
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_TLP;
        return (0);
}

/*
 * Delayed ack Timer, here we simply need to setup the
 * ACK_NOW flag and remove the DELACK flag. From there
 * the output routine will send the ack out.
 *
 * We only return 1, saying don't proceed, if all timers
 * are stopped (destroyed PCB?).
 */
static int
rack_timeout_delack(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts)
{

        rack_log_to_event(rack, RACK_TO_FRM_DELACK, NULL);
        tp->t_flags &= ~TF_DELACK;
        tp->t_flags |= TF_ACKNOW;
        KMOD_TCPSTAT_INC(tcps_delack);
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_DELACK;
        return (0);
}

static inline int
rack_send_ack_challange(struct tcp_rack *rack)
{
        struct tcptemp *t_template;

        t_template = tcpip_maketemplate(rack->rc_inp);
        if (t_template) {
                if (rack->forced_ack == 0) {
                        rack->forced_ack = 1;
                        rack->r_ctl.forced_ack_ts = tcp_get_usecs(NULL);
                } else {
                        rack->probe_not_answered = 1;
                }
                tcp_respond(rack->rc_tp, t_template->tt_ipgen,
                            &t_template->tt_t, (struct mbuf *)NULL,
                            rack->rc_tp->rcv_nxt, rack->rc_tp->snd_una - 1, 0);
                free(t_template, M_TEMP);
                /* This does send an ack so kill any D-ack timer */
                if (rack->rc_tp->t_flags & TF_DELACK)
                        rack->rc_tp->t_flags &= ~TF_DELACK;
                return(1);
        } else
                return (0);

}

/*
 * Persists timer, here we simply send the
 * same thing as a keepalive will.
 * the one byte send.
 *
 * We only return 1, saying don't proceed, if all timers
 * are stopped (destroyed PCB?).
 */
static int
rack_timeout_persist(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts)
{
        int32_t retval = 1;

        if (rack->rc_in_persist == 0)
                return (0);
        if (ctf_progress_timeout_check(tp, false)) {
                tcp_log_end_status(tp, TCP_EI_STATUS_PERSIST_MAX);
                rack_log_progress_event(rack, tp, tick, PROGRESS_DROP, __LINE__);
                counter_u64_add(rack_persists_lost_ends, rack->r_ctl.persist_lost_ends);
                return (-ETIMEDOUT);    /* tcp_drop() */
        }
        /*
         * Persistence timer into zero window. Force a byte to be output, if
         * possible.
         */
        KMOD_TCPSTAT_INC(tcps_persisttimeo);
        /*
         * Hack: if the peer is dead/unreachable, we do not time out if the
         * window is closed.  After a full backoff, drop the connection if
         * the idle time (no responses to probes) reaches the maximum
         * backoff that we would use if retransmitting.
         */
        if (tp->t_rxtshift >= V_tcp_retries &&
            (ticks - tp->t_rcvtime >= tcp_maxpersistidle ||
             TICKS_2_USEC(ticks - tp->t_rcvtime) >= RACK_REXMTVAL(tp) * tcp_totbackoff)) {
                KMOD_TCPSTAT_INC(tcps_persistdrop);
                tcp_log_end_status(tp, TCP_EI_STATUS_PERSIST_MAX);
                counter_u64_add(rack_persists_lost_ends, rack->r_ctl.persist_lost_ends);
                retval = -ETIMEDOUT;    /* tcp_drop() */
                goto out;
        }
        if ((sbavail(&rack->rc_inp->inp_socket->so_snd) == 0) &&
            tp->snd_una == tp->snd_max)
                rack_exit_persist(tp, rack, cts);
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_PERSIT;
        /*
         * If the user has closed the socket then drop a persisting
         * connection after a much reduced timeout.
         */
        if (tp->t_state > TCPS_CLOSE_WAIT &&
            (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) {
                KMOD_TCPSTAT_INC(tcps_persistdrop);
                tcp_log_end_status(tp, TCP_EI_STATUS_PERSIST_MAX);
                counter_u64_add(rack_persists_lost_ends, rack->r_ctl.persist_lost_ends);
                retval = -ETIMEDOUT;    /* tcp_drop() */
                goto out;
        }
        if (rack_send_ack_challange(rack)) {
                /* only set it if we were answered */
                if (rack->probe_not_answered) {
                        counter_u64_add(rack_persists_loss, 1);
                        rack->r_ctl.persist_lost_ends++;
                }
                counter_u64_add(rack_persists_sends, 1);
                counter_u64_add(rack_out_size[TCP_MSS_ACCT_PERSIST], 1);
        }
        if (tp->t_rxtshift < V_tcp_retries)
                tp->t_rxtshift++;
out:
        rack_log_to_event(rack, RACK_TO_FRM_PERSIST, NULL);
        rack_start_hpts_timer(rack, tp, cts,
                              0, 0, 0);
        return (retval);
}

/*
 * If a keepalive goes off, we had no other timers
 * happening. We always return 1 here since this
 * routine either drops the connection or sends
 * out a segment with respond.
 */
static int
rack_timeout_keepalive(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts)
{
        struct inpcb *inp = tptoinpcb(tp);

        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_KEEP;
        rack_log_to_event(rack, RACK_TO_FRM_KEEP, NULL);
        /*
         * Keep-alive timer went off; send something or drop connection if
         * idle for too long.
         */
        KMOD_TCPSTAT_INC(tcps_keeptimeo);
        if (tp->t_state < TCPS_ESTABLISHED)
                goto dropit;
        if ((V_tcp_always_keepalive || inp->inp_socket->so_options & SO_KEEPALIVE) &&
            tp->t_state <= TCPS_CLOSING) {
                if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp))
                        goto dropit;
                /*
                 * Send a packet designed to force a response if the peer is
                 * up and reachable: either an ACK if the connection is
                 * still alive, or an RST if the peer has closed the
                 * connection due to timeout or reboot. Using sequence
                 * number tp->snd_una-1 causes the transmitted zero-length
                 * segment to lie outside the receive window; by the
                 * protocol spec, this requires the correspondent TCP to
                 * respond.
                 */
                KMOD_TCPSTAT_INC(tcps_keepprobe);
                rack_send_ack_challange(rack);
        }
        rack_start_hpts_timer(rack, tp, cts, 0, 0, 0);
        return (1);
dropit:
        KMOD_TCPSTAT_INC(tcps_keepdrops);
        tcp_log_end_status(tp, TCP_EI_STATUS_KEEP_MAX);
        return (-ETIMEDOUT);    /* tcp_drop() */
}

/*
 * Retransmit helper function, clear up all the ack
 * flags and take care of important book keeping.
 */
static void
rack_remxt_tmr(struct tcpcb *tp)
{
        /*
         * The retransmit timer went off, all sack'd blocks must be
         * un-acked.
         */
        struct rack_sendmap *rsm, *trsm = NULL;
        struct tcp_rack *rack;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        rack_timer_cancel(tp, rack, tcp_get_usecs(NULL), __LINE__);
        rack_log_to_event(rack, RACK_TO_FRM_TMR, NULL);
        rack->r_timer_override = 1;
        rack->r_ctl.rc_snd_max_at_rto = tp->snd_max;
        rack->r_ctl.rc_last_timeout_snduna = tp->snd_una;
        rack->r_late = 0;
        rack->r_early = 0;
        rack->r_ctl.rc_agg_delayed = 0;
        rack->r_ctl.rc_agg_early = 0;
        if (rack->r_state && (rack->r_state != tp->t_state))
                rack_set_state(tp, rack);
        if (tp->t_rxtshift <= rack_rxt_scoreboard_clear_thresh) {
                /*
                 * We do not clear the scoreboard until we have had
                 * more than rack_rxt_scoreboard_clear_thresh time-outs.
                 */
                rack->r_ctl.rc_resend = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
                if (rack->r_ctl.rc_resend != NULL)
                        rack->r_ctl.rc_resend->r_flags |= RACK_TO_REXT;

                return;
        }
        /*
         * Ideally we would like to be able to
         * mark SACK-PASS on anything not acked here.
         *
         * However, if we do that we would burst out
         * all that data 1ms apart. This would be unwise,
         * so for now we will just let the normal rxt timer
         * and tlp timer take care of it.
         *
         * Also we really need to stick them back in sequence
         * order. This way we send in the proper order and any
         * sacks that come floating in will "re-ack" the data.
         * To do this we zap the tmap with an INIT and then
         * walk through and place every rsm in the tail queue
         * hash table back in its seq ordered place.
         */
        TAILQ_INIT(&rack->r_ctl.rc_tmap);

        rack->r_ctl.recovery_rxt_cnt = 0;
        TQHASH_FOREACH(rsm, rack->r_ctl.tqh)  {
                rsm->r_dupack = 0;
                if (rack_verbose_logging)
                        rack_log_retran_reason(rack, rsm, __LINE__, 0, 2);
                /* We must re-add it back to the tlist */
                if (trsm == NULL) {
                        TAILQ_INSERT_HEAD(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                } else {
                        TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, trsm, rsm, r_tnext);
                }
                rsm->r_in_tmap = 1;
                trsm = rsm;
                if (rsm->r_flags & RACK_ACKED)
                        rsm->r_flags |= RACK_WAS_ACKED;
                rsm->r_flags &= ~(RACK_ACKED | RACK_SACK_PASSED | RACK_WAS_SACKPASS | RACK_RWND_COLLAPSED | RACK_WAS_LOST);
                rsm->r_flags |= RACK_MUST_RXT;
        }
        /* zero the lost since it's all gone */
        rack->r_ctl.rc_considered_lost = 0;
        /* Clear the count (we just un-acked them) */
        rack->r_ctl.rc_sacked = 0;
        rack->r_ctl.rc_sacklast = NULL;
        /* Clear the tlp rtx mark */
        rack->r_ctl.rc_resend = tqhash_min(rack->r_ctl.tqh);
        if (rack->r_ctl.rc_resend != NULL)
                rack->r_ctl.rc_resend->r_flags |= RACK_TO_REXT;
        rack->r_ctl.rc_prr_sndcnt = 0;
        rack_log_to_prr(rack, 6, 0, __LINE__);
        rack->r_ctl.rc_resend = tqhash_min(rack->r_ctl.tqh);
        if (rack->r_ctl.rc_resend != NULL)
                rack->r_ctl.rc_resend->r_flags |= RACK_TO_REXT;
        if (((tp->t_flags & TF_SACK_PERMIT) == 0) &&
            ((tp->t_flags & TF_SENTFIN) == 0)) {
                /*
                 * For non-sack customers new data
                 * needs to go out as retransmits until
                 * we retransmit up to snd_max.
                 */
                rack->r_must_retran = 1;
                rack->r_ctl.rc_out_at_rto = ctf_flight_size(rack->rc_tp,
                                                            rack->r_ctl.rc_sacked);
        }
}

static void
rack_convert_rtts(struct tcpcb *tp)
{
        tcp_change_time_units(tp, TCP_TMR_GRANULARITY_USEC);
        tp->t_rxtcur = RACK_REXMTVAL(tp);
        if (TCPS_HAVEESTABLISHED(tp->t_state)) {
                tp->t_rxtcur += TICKS_2_USEC(tcp_rexmit_slop);
        }
        if (tp->t_rxtcur > rack_rto_max) {
                tp->t_rxtcur = rack_rto_max;
        }
}

static void
rack_cc_conn_init(struct tcpcb *tp)
{
        struct tcp_rack *rack;
        uint32_t srtt;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        srtt = tp->t_srtt;
        cc_conn_init(tp);
        /*
         * Now convert to rack's internal format,
         * if required.
         */
        if ((srtt == 0) && (tp->t_srtt != 0))
                rack_convert_rtts(tp);
        /*
         * We want a chance to stay in slowstart as
         * we create a connection. TCP spec says that
         * initially ssthresh is infinite. For our
         * purposes that is the snd_wnd.
         */
        if (tp->snd_ssthresh < tp->snd_wnd) {
                tp->snd_ssthresh = tp->snd_wnd;
        }
        /*
         * We also want to assure a IW worth of
         * data can get inflight.
         */
        if (rc_init_window(rack) < tp->snd_cwnd)
                tp->snd_cwnd = rc_init_window(rack);
}

/*
 * Re-transmit timeout! If we drop the PCB we will return 1, otherwise
 * we will setup to retransmit the lowest seq number outstanding.
 */
static int
rack_timeout_rxt(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts)
{
        struct inpcb *inp = tptoinpcb(tp);
        int32_t rexmt;
        int32_t retval = 0;
        bool isipv6;

        if ((tp->t_flags & TF_GPUTINPROG) &&
            (tp->t_rxtshift)) {
                /*
                 * We have had a second timeout
                 * measurements on successive rxt's are not profitable.
                 * It is unlikely to be of any use (the network is
                 * broken or the client went away).
                 */
                tp->t_flags &= ~TF_GPUTINPROG;
                rack_log_pacing_delay_calc(rack, (tp->gput_ack - tp->gput_seq) /*flex2*/,
                                           rack->r_ctl.rc_gp_srtt /*flex1*/,
                                           tp->gput_seq,
                                           0, 0, 18, __LINE__, NULL, 0);
        }
        if (ctf_progress_timeout_check(tp, false)) {
                tcp_log_end_status(tp, TCP_EI_STATUS_RETRAN);
                rack_log_progress_event(rack, tp, tick, PROGRESS_DROP, __LINE__);
                return (-ETIMEDOUT);    /* tcp_drop() */
        }
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_RXT;
        rack->r_ctl.retran_during_recovery = 0;
        rack->rc_ack_required = 1;
        rack->r_ctl.dsack_byte_cnt = 0;
        if (IN_RECOVERY(tp->t_flags) &&
            (rack->rto_from_rec == 0)) {
                /*
                 * Mark that we had a rto while in recovery
                 * and save the ssthresh so if we go back
                 * into recovery we will have a chance
                 * to slowstart back to the level.
                 */
                rack->rto_from_rec = 1;
                rack->r_ctl.rto_ssthresh = tp->snd_ssthresh;
        }
        if (IN_FASTRECOVERY(tp->t_flags))
                tp->t_flags |= TF_WASFRECOVERY;
        else
                tp->t_flags &= ~TF_WASFRECOVERY;
        if (IN_CONGRECOVERY(tp->t_flags))
                tp->t_flags |= TF_WASCRECOVERY;
        else
                tp->t_flags &= ~TF_WASCRECOVERY;
        if (TCPS_HAVEESTABLISHED(tp->t_state) &&
            (tp->snd_una == tp->snd_max)) {
                /* Nothing outstanding .. nothing to do */
                return (0);
        }
        if (rack->r_ctl.dsack_persist) {
                rack->r_ctl.dsack_persist--;
                if (rack->r_ctl.num_dsack && (rack->r_ctl.dsack_persist == 0)) {
                        rack->r_ctl.num_dsack = 0;
                }
                rack_log_dsack_event(rack, 1, __LINE__, 0, 0);
        }
        /*
         * Rack can only run one timer  at a time, so we cannot
         * run a KEEPINIT (gating SYN sending) and a retransmit
         * timer for the SYN. So if we are in a front state and
         * have a KEEPINIT timer we need to check the first transmit
         * against now to see if we have exceeded the KEEPINIT time
         * (if one is set).
         */
        if ((TCPS_HAVEESTABLISHED(tp->t_state) == 0) &&
            (TP_KEEPINIT(tp) != 0)) {
                struct rack_sendmap *rsm;

                rsm = tqhash_min(rack->r_ctl.tqh);
                if (rsm) {
                        /* Ok we have something outstanding to test keepinit with */
                        if ((TSTMP_GT(cts, (uint32_t)rsm->r_tim_lastsent[0])) &&
                            ((cts - (uint32_t)rsm->r_tim_lastsent[0]) >= TICKS_2_USEC(TP_KEEPINIT(tp)))) {
                                /* We have exceeded the KEEPINIT time */
                                tcp_log_end_status(tp, TCP_EI_STATUS_KEEP_MAX);
                                goto drop_it;
                        }
                }
        }
        /*
         * Retransmission timer went off.  Message has not been acked within
         * retransmit interval.  Back off to a longer retransmit interval
         * and retransmit one segment.
         */
        if ((rack->r_ctl.rc_resend == NULL) ||
            ((rack->r_ctl.rc_resend->r_flags & RACK_RWND_COLLAPSED) == 0)) {
                /*
                 * If the rwnd collapsed on
                 * the one we are retransmitting
                 * it does not count against the
                 * rxt count.
                 */
                tp->t_rxtshift++;
        }
        rack_remxt_tmr(tp);
        if (tp->t_rxtshift > V_tcp_retries) {
                tcp_log_end_status(tp, TCP_EI_STATUS_RETRAN);
drop_it:
                tp->t_rxtshift = V_tcp_retries;
                KMOD_TCPSTAT_INC(tcps_timeoutdrop);
                /* XXXGL: previously t_softerror was casted to uint16_t */
                MPASS(tp->t_softerror >= 0);
                retval = tp->t_softerror ? -tp->t_softerror : -ETIMEDOUT;
                goto out;       /* tcp_drop() */
        }
        if (tp->t_state == TCPS_SYN_SENT) {
                /*
                 * If the SYN was retransmitted, indicate CWND to be limited
                 * to 1 segment in cc_conn_init().
                 */
                tp->snd_cwnd = 1;
        } else if (tp->t_rxtshift == 1) {
                /*
                 * first retransmit; record ssthresh and cwnd so they can be
                 * recovered if this turns out to be a "bad" retransmit. A
                 * retransmit is considered "bad" if an ACK for this segment
                 * is received within RTT/2 interval; the assumption here is
                 * that the ACK was already in flight.  See "On Estimating
                 * End-to-End Network Path Properties" by Allman and Paxson
                 * for more details.
                 */
                tp->snd_cwnd_prev = tp->snd_cwnd;
                tp->snd_ssthresh_prev = tp->snd_ssthresh;
                tp->snd_recover_prev = tp->snd_recover;
                tp->t_badrxtwin = ticks + (USEC_2_TICKS(tp->t_srtt)/2);
                tp->t_flags |= TF_PREVVALID;
        } else if ((tp->t_flags & TF_RCVD_TSTMP) == 0)
                tp->t_flags &= ~TF_PREVVALID;
        KMOD_TCPSTAT_INC(tcps_rexmttimeo);
        if ((tp->t_state == TCPS_SYN_SENT) ||
            (tp->t_state == TCPS_SYN_RECEIVED))
                rexmt = RACK_INITIAL_RTO * tcp_backoff[tp->t_rxtshift];
        else
                rexmt = max(rack_rto_min, (tp->t_srtt + (tp->t_rttvar << 2))) * tcp_backoff[tp->t_rxtshift];

        RACK_TCPT_RANGESET(tp->t_rxtcur, rexmt,
           max(rack_rto_min, rexmt), rack_rto_max, rack->r_ctl.timer_slop);
        /*
         * We enter the path for PLMTUD if connection is established or, if
         * connection is FIN_WAIT_1 status, reason for the last is that if
         * amount of data we send is very small, we could send it in couple
         * of packets and process straight to FIN. In that case we won't
         * catch ESTABLISHED state.
         */
#ifdef INET6
        isipv6 = (inp->inp_vflag & INP_IPV6) ? true : false;
#else
        isipv6 = false;
#endif
        if (((V_tcp_pmtud_blackhole_detect == 1) ||
            (V_tcp_pmtud_blackhole_detect == 2 && !isipv6) ||
            (V_tcp_pmtud_blackhole_detect == 3 && isipv6)) &&
            ((tp->t_state == TCPS_ESTABLISHED) ||
            (tp->t_state == TCPS_FIN_WAIT_1))) {
                /*
                 * Idea here is that at each stage of mtu probe (usually,
                 * 1448 -> 1188 -> 524) should be given 2 chances to recover
                 * before further clamping down. 'tp->t_rxtshift % 2 == 0'
                 * should take care of that.
                 */
                if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD | TF2_PLPMTU_MAXSEGSNT)) ==
                    (TF2_PLPMTU_PMTUD | TF2_PLPMTU_MAXSEGSNT)) &&
                    (tp->t_rxtshift >= 2 && tp->t_rxtshift < 6 &&
                    tp->t_rxtshift % 2 == 0)) {
                        /*
                         * Enter Path MTU Black-hole Detection mechanism: -
                         * Disable Path MTU Discovery (IP "DF" bit). -
                         * Reduce MTU to lower value than what we negotiated
                         * with peer.
                         */
                        if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) {
                                /* Record that we may have found a black hole. */
                                tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE;
                                /* Keep track of previous MSS. */
                                tp->t_pmtud_saved_maxseg = tp->t_maxseg;
                        }

                        /*
                         * Reduce the MSS to blackhole value or to the
                         * default in an attempt to retransmit.
                         */
#ifdef INET6
                        if (isipv6 &&
                            tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) {
                                /* Use the sysctl tuneable blackhole MSS. */
                                tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss;
                                KMOD_TCPSTAT_INC(tcps_pmtud_blackhole_activated);
                        } else if (isipv6) {
                                /* Use the default MSS. */
                                tp->t_maxseg = V_tcp_v6mssdflt;
                                /*
                                 * Disable Path MTU Discovery when we switch
                                 * to minmss.
                                 */
                                tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
                                KMOD_TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss);
                        }
#endif
#if defined(INET6) && defined(INET)
                        else
#endif
#ifdef INET
                        if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) {
                                /* Use the sysctl tuneable blackhole MSS. */
                                tp->t_maxseg = V_tcp_pmtud_blackhole_mss;
                                KMOD_TCPSTAT_INC(tcps_pmtud_blackhole_activated);
                        } else {
                                /* Use the default MSS. */
                                tp->t_maxseg = V_tcp_mssdflt;
                                /*
                                 * Disable Path MTU Discovery when we switch
                                 * to minmss.
                                 */
                                tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
                                KMOD_TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss);
                        }
#endif
                } else {
                        /*
                         * If further retransmissions are still unsuccessful
                         * with a lowered MTU, maybe this isn't a blackhole
                         * and we restore the previous MSS and blackhole
                         * detection flags. The limit '6' is determined by
                         * giving each probe stage (1448, 1188, 524) 2
                         * chances to recover.
                         */
                        if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) &&
                            (tp->t_rxtshift >= 6)) {
                                tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                                tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE;
                                tp->t_maxseg = tp->t_pmtud_saved_maxseg;
                                if (tp->t_maxseg < V_tcp_mssdflt) {
                                        /*
                                         * The MSS is so small we should not
                                         * process incoming SACK's since we are
                                         * subject to attack in such a case.
                                         */
                                        tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT;
                                } else {
                                        tp->t_flags2 &= ~TF2_PROC_SACK_PROHIBIT;
                                }
                                KMOD_TCPSTAT_INC(tcps_pmtud_blackhole_failed);
                        }
                }
        }
        /*
         * Disable RFC1323 and SACK if we haven't got any response to
         * our third SYN to work-around some broken terminal servers
         * (most of which have hopefully been retired) that have bad VJ
         * header compression code which trashes TCP segments containing
         * unknown-to-them TCP options.
         */
        if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) &&
            (tp->t_rxtshift == 3))
                tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT);
        /*
         * If we backed off this far, our srtt estimate is probably bogus.
         * Clobber it so we'll take the next rtt measurement as our srtt;
         * move the current srtt into rttvar to keep the current retransmit
         * times until then.
         */
        if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
#ifdef INET6
                if ((inp->inp_vflag & INP_IPV6) != 0)
                        in6_losing(inp);
                else
#endif
                        in_losing(inp);
                tp->t_rttvar += tp->t_srtt;
                tp->t_srtt = 0;
        }
        sack_filter_clear(&rack->r_ctl.rack_sf, tp->snd_una);
        tp->snd_recover = tp->snd_max;
        tp->t_flags |= TF_ACKNOW;
        tp->t_rtttime = 0;
        rack_cong_signal(tp, CC_RTO, tp->snd_una, __LINE__);
out:
        return (retval);
}

static int
rack_process_timers(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts, uint8_t hpts_calling, uint8_t *doing_tlp)
{
        int32_t ret = 0;
        int32_t timers = (rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK);

        if ((tp->t_state >= TCPS_FIN_WAIT_1) &&
            (tp->t_flags & TF_GPUTINPROG)) {
                /*
                 * We have a goodput in progress
                 * and we have entered a late state.
                 * Do we have enough data in the sb
                 * to handle the GPUT request?
                 */
                uint32_t bytes;

                bytes = tp->gput_ack - tp->gput_seq;
                if (SEQ_GT(tp->gput_seq, tp->snd_una))
                        bytes += tp->gput_seq - tp->snd_una;
                if (bytes > sbavail(&tptosocket(tp)->so_snd)) {
                        /*
                         * There are not enough bytes in the socket
                         * buffer that have been sent to cover this
                         * measurement. Cancel it.
                         */
                        rack_log_pacing_delay_calc(rack, (tp->gput_ack - tp->gput_seq) /*flex2*/,
                                                   rack->r_ctl.rc_gp_srtt /*flex1*/,
                                                   tp->gput_seq,
                                                   0, 0, 18, __LINE__, NULL, 0);
                        tp->t_flags &= ~TF_GPUTINPROG;
                }
        }
        if (timers == 0) {
                return (0);
        }
        if (tp->t_state == TCPS_LISTEN) {
                /* no timers on listen sockets */
                if (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT)
                        return (0);
                return (1);
        }
        if ((timers & PACE_TMR_RACK) &&
            rack->rc_on_min_to) {
                /*
                 * For the rack timer when we
                 * are on a min-timeout (which means rrr_conf = 3)
                 * we don't want to check the timer. It may
                 * be going off for a pace and thats ok we
                 * want to send the retransmit (if its ready).
                 *
                 * If its on a normal rack timer (non-min) then
                 * we will check if its expired.
                 */
                goto skip_time_check;
        }
        if (TSTMP_LT(cts, rack->r_ctl.rc_timer_exp)) {
                uint32_t left;

                if (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) {
                        ret = -1;
                        rack_log_to_processing(rack, cts, ret, 0);
                        return (0);
                }
                if (hpts_calling == 0) {
                        /*
                         * A user send or queued mbuf (sack) has called us? We
                         * return 0 and let the pacing guards
                         * deal with it if they should or
                         * should not cause a send.
                         */
                        ret = -2;
                        rack_log_to_processing(rack, cts, ret, 0);
                        return (0);
                }
                /*
                 * Ok our timer went off early and we are not paced false
                 * alarm, go back to sleep. We make sure we don't have
                 * no-sack wakeup on since we no longer have a PKT_OUTPUT
                 * flag in place.
                 */
                rack->rc_tp->t_flags2 &= ~TF2_DONT_SACK_QUEUE;
                ret = -3;
                left = rack->r_ctl.rc_timer_exp - cts;
                tcp_hpts_insert(tp, left, NULL);
                rack_log_to_processing(rack, cts, ret, left);
                return (1);
        }
skip_time_check:
        rack->rc_tmr_stopped = 0;
        rack->r_ctl.rc_hpts_flags &= ~PACE_TMR_MASK;
        if (timers & PACE_TMR_DELACK) {
                ret = rack_timeout_delack(tp, rack, cts);
        } else if (timers & PACE_TMR_RACK) {
                rack->r_ctl.rc_tlp_rxt_last_time = cts;
                rack->r_fast_output = 0;
                ret = rack_timeout_rack(tp, rack, cts);
        } else if (timers & PACE_TMR_TLP) {
                rack->r_ctl.rc_tlp_rxt_last_time = cts;
                rack->r_fast_output = 0;
                ret = rack_timeout_tlp(tp, rack, cts, doing_tlp);
        } else if (timers & PACE_TMR_RXT) {
                rack->r_ctl.rc_tlp_rxt_last_time = cts;
                rack->r_fast_output = 0;
                ret = rack_timeout_rxt(tp, rack, cts);
        } else if (timers & PACE_TMR_PERSIT) {
                ret = rack_timeout_persist(tp, rack, cts);
        } else if (timers & PACE_TMR_KEEP) {
                ret = rack_timeout_keepalive(tp, rack, cts);
        }
        rack_log_to_processing(rack, cts, ret, timers);
        return (ret);
}

static void
rack_timer_cancel(struct tcpcb *tp, struct tcp_rack *rack, uint32_t cts, int line)
{
        struct timeval tv;
        uint32_t us_cts, flags_on_entry;
        uint8_t hpts_removed = 0;

        flags_on_entry = rack->r_ctl.rc_hpts_flags;
        us_cts = tcp_get_usecs(&tv);
        if ((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) &&
            ((TSTMP_GEQ(us_cts, rack->r_ctl.rc_last_output_to)) ||
             ((tp->snd_max - tp->snd_una) == 0))) {
                tcp_hpts_remove(rack->rc_tp);
                hpts_removed = 1;
                /* If we were not delayed cancel out the flag. */
                if ((tp->snd_max - tp->snd_una) == 0)
                        rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
                rack_log_to_cancel(rack, hpts_removed, line, us_cts, &tv, flags_on_entry);
        }
        if (rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK) {
                rack->rc_tmr_stopped = rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK;
                if (tcp_in_hpts(rack->rc_tp) &&
                    ((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) == 0)) {
                        /*
                         * Canceling timer's when we have no output being
                         * paced. We also must remove ourselves from the
                         * hpts.
                         */
                        tcp_hpts_remove(rack->rc_tp);
                        hpts_removed = 1;
                }
                rack->r_ctl.rc_hpts_flags &= ~(PACE_TMR_MASK);
        }
        if (hpts_removed == 0)
                rack_log_to_cancel(rack, hpts_removed, line, us_cts, &tv, flags_on_entry);
}

static int
rack_stopall(struct tcpcb *tp)
{
        struct tcp_rack *rack;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        rack->t_timers_stopped = 1;

        tcp_hpts_remove(tp);

        return (0);
}

static void
rack_stop_all_timers(struct tcpcb *tp, struct tcp_rack *rack)
{
        /*
         * Assure no timers are running.
         */
        if (tcp_timer_active(tp, TT_PERSIST)) {
                /* We enter in persists, set the flag appropriately */
                rack->rc_in_persist = 1;
        }
        if (tcp_in_hpts(rack->rc_tp)) {
                tcp_hpts_remove(rack->rc_tp);
        }
}

static void
rack_update_rsm(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, uint64_t ts, uint32_t add_flag, int segsiz)
{
        int32_t idx;

        rsm->r_rtr_cnt++;
        if (rsm->r_rtr_cnt > RACK_NUM_OF_RETRANS) {
                rsm->r_rtr_cnt = RACK_NUM_OF_RETRANS;
                rsm->r_flags |= RACK_OVERMAX;
        }
        rsm->r_act_rxt_cnt++;
        /* Peg the count/index */
        rack_log_retran_reason(rack, rsm, __LINE__, 0, 2);
        rsm->r_dupack = 0;
        if ((rsm->r_rtr_cnt > 1) && ((rsm->r_flags & RACK_TLP) == 0)) {
                rack->r_ctl.rc_holes_rxt += (rsm->r_end - rsm->r_start);
                rsm->r_rtr_bytes += (rsm->r_end - rsm->r_start);
        }
        if (rsm->r_flags & RACK_WAS_LOST) {
                /*
                 * We retransmitted it putting it back in flight
                 * remove the lost desgination and reduce the
                 * bytes considered lost.
                 */
                rack_mark_nolonger_lost(rack, rsm);
        }
        idx = rsm->r_rtr_cnt - 1;
        rsm->r_tim_lastsent[idx] = ts;
        /*
         * Here we don't add in the len of send, since its already
         * in snduna <->snd_max.
         */
        rsm->r_fas = ctf_flight_size(rack->rc_tp,
                                     rack->r_ctl.rc_sacked);
        if (rsm->r_flags & RACK_ACKED) {
                /* Problably MTU discovery messing with us */
                rsm->r_flags &= ~RACK_ACKED;
                rack->r_ctl.rc_sacked -= (rsm->r_end - rsm->r_start);
        }
        if (rsm->r_in_tmap) {
                TAILQ_REMOVE(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                rsm->r_in_tmap = 0;
        }
        /* Lets make sure it really is in or not the GP window */
        rack_mark_in_gp_win(tp, rsm);
        TAILQ_INSERT_TAIL(&rack->r_ctl.rc_tmap, rsm, r_tnext);
        rsm->r_in_tmap = 1;
        rsm->r_bas = (uint8_t)(((rsm->r_end - rsm->r_start) + segsiz - 1) / segsiz);
        /* Take off the must retransmit flag, if its on */
        if (rsm->r_flags & RACK_MUST_RXT) {
                if (rack->r_must_retran)
                        rack->r_ctl.rc_out_at_rto -= (rsm->r_end - rsm->r_start);
                if (SEQ_GEQ(rsm->r_end, rack->r_ctl.rc_snd_max_at_rto)) {
                        /*
                         * We have retransmitted all we need. Clear
                         * any must retransmit flags.
                         */
                        rack->r_must_retran = 0;
                        rack->r_ctl.rc_out_at_rto = 0;
                }
                rsm->r_flags &= ~RACK_MUST_RXT;
        }
        /* Remove any collapsed flag */
        rsm->r_flags &= ~RACK_RWND_COLLAPSED;
        if (rsm->r_flags & RACK_SACK_PASSED) {
                /* We have retransmitted due to the SACK pass */
                rsm->r_flags &= ~RACK_SACK_PASSED;
                rsm->r_flags |= RACK_WAS_SACKPASS;
                rack->r_ctl.recovery_rxt_cnt += (rsm->r_end - rsm->r_start);
        }
}

static uint32_t
rack_update_entry(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, uint64_t ts, int32_t *lenp, uint32_t add_flag, int segsiz)
{
        /*
         * We (re-)transmitted starting at rsm->r_start for some length
         * (possibly less than r_end.
         */
        struct rack_sendmap *nrsm;
        int insret __diagused;
        uint32_t c_end;
        int32_t len;

        len = *lenp;
        c_end = rsm->r_start + len;
        if (SEQ_GEQ(c_end, rsm->r_end)) {
                /*
                 * We retransmitted the whole piece or more than the whole
                 * slopping into the next rsm.
                 */
                rack_update_rsm(tp, rack, rsm, ts, add_flag, segsiz);
                if (c_end == rsm->r_end) {
                        *lenp = 0;
                        return (0);
                } else {
                        int32_t act_len;

                        /* Hangs over the end return whats left */
                        act_len = rsm->r_end - rsm->r_start;
                        *lenp = (len - act_len);
                        return (rsm->r_end);
                }
                /* We don't get out of this block. */
        }
        /*
         * Here we retransmitted less than the whole thing which means we
         * have to split this into what was transmitted and what was not.
         */
        nrsm = rack_alloc_full_limit(rack);
        if (nrsm == NULL) {
                /*
                 * We can't get memory, so lets not proceed.
                 */
                *lenp = 0;
                return (0);
        }
        /*
         * So here we are going to take the original rsm and make it what we
         * retransmitted. nrsm will be the tail portion we did not
         * retransmit. For example say the chunk was 1, 11 (10 bytes). And
         * we retransmitted 5 bytes i.e. 1, 5. The original piece shrinks to
         * 1, 6 and the new piece will be 6, 11.
         */
        rack_clone_rsm(rack, nrsm, rsm, c_end);
        nrsm->r_dupack = 0;
        rack_log_retran_reason(rack, nrsm, __LINE__, 0, 2);
#ifndef INVARIANTS
        (void)tqhash_insert(rack->r_ctl.tqh, nrsm);
#else
        if ((insret = tqhash_insert(rack->r_ctl.tqh, nrsm)) != 0) {
                panic("Insert in tailq_hash of %p fails ret:%d rack:%p rsm:%p",
                      nrsm, insret, rack, rsm);
        }
#endif
        if (rsm->r_in_tmap) {
                TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, rsm, nrsm, r_tnext);
                nrsm->r_in_tmap = 1;
        }
        rsm->r_flags &= (~RACK_HAS_FIN);
        rack_update_rsm(tp, rack, rsm, ts, add_flag, segsiz);
        /* Log a split of rsm into rsm and nrsm */
        rack_log_map_chg(tp, rack, NULL, rsm, nrsm, MAP_SPLIT, 0, __LINE__);
        *lenp = 0;
        return (0);
}

static void
rack_log_output(struct tcpcb *tp, struct tcpopt *to, int32_t len,
                uint32_t seq_out, uint16_t th_flags, int32_t err, uint64_t cts,
                struct rack_sendmap *hintrsm, uint32_t add_flag, struct mbuf *s_mb,
                uint32_t s_moff, int hw_tls, int segsiz)
{
        struct tcp_rack *rack;
        struct rack_sendmap *rsm, *nrsm;
        int insret __diagused;

        register uint32_t snd_max, snd_una;

        /*
         * Add to the RACK log of packets in flight or retransmitted. If
         * there is a TS option we will use the TS echoed, if not we will
         * grab a TS.
         *
         * Retransmissions will increment the count and move the ts to its
         * proper place. Note that if options do not include TS's then we
         * won't be able to effectively use the ACK for an RTT on a retran.
         *
         * Notes about r_start and r_end. Lets consider a send starting at
         * sequence 1 for 10 bytes. In such an example the r_start would be
         * 1 (starting sequence) but the r_end would be r_start+len i.e. 11.
         * This means that r_end is actually the first sequence for the next
         * slot (11).
         *
         */
        /*
         * If err is set what do we do XXXrrs? should we not add the thing?
         * -- i.e. return if err != 0 or should we pretend we sent it? --
         * i.e. proceed with add ** do this for now.
         */
        INP_WLOCK_ASSERT(tptoinpcb(tp));
        if (err)
                /*
                 * We don't log errors -- we could but snd_max does not
                 * advance in this case either.
                 */
                return;

        if (th_flags & TH_RST) {
                /*
                 * We don't log resets and we return immediately from
                 * sending
                 */
                return;
        }
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        snd_una = tp->snd_una;
        snd_max = tp->snd_max;
        if (th_flags & (TH_SYN | TH_FIN)) {
                /*
                 * The call to rack_log_output is made before bumping
                 * snd_max. This means we can record one extra byte on a SYN
                 * or FIN if seq_out is adding more on and a FIN is present
                 * (and we are not resending).
                 */
                if ((th_flags & TH_SYN) && (seq_out == tp->iss))
                        len++;
                if (th_flags & TH_FIN)
                        len++;
        }
        if (SEQ_LEQ((seq_out + len), snd_una)) {
                /* Are sending an old segment to induce an ack (keep-alive)? */
                return;
        }
        if (SEQ_LT(seq_out, snd_una)) {
                /* huh? should we panic? */
                uint32_t end;

                end = seq_out + len;
                seq_out = snd_una;
                if (SEQ_GEQ(end, seq_out))
                        len = end - seq_out;
                else
                        len = 0;
        }
        if (len == 0) {
                /* We don't log zero window probes */
                return;
        }
        if (IN_FASTRECOVERY(tp->t_flags)) {
                rack->r_ctl.rc_prr_out += len;
        }
        /* First question is it a retransmission or new? */
        if (seq_out == snd_max) {
                /* Its new */
                rack_chk_req_and_hybrid_on_out(rack, seq_out, len, cts);
again:
                rsm = rack_alloc(rack);
                if (rsm == NULL) {
                        /*
                         * Hmm out of memory and the tcb got destroyed while
                         * we tried to wait.
                         */
                        return;
                }
                if (th_flags & TH_FIN) {
                        rsm->r_flags = RACK_HAS_FIN|add_flag;
                } else {
                        rsm->r_flags = add_flag;
                }
                if (hw_tls)
                        rsm->r_hw_tls = 1;
                rsm->r_tim_lastsent[0] = cts;
                rsm->r_rtr_cnt = 1;
                rsm->r_act_rxt_cnt = 0;
                rsm->r_rtr_bytes = 0;
                if (th_flags & TH_SYN) {
                        /* The data space is one beyond snd_una */
                        rsm->r_flags |= RACK_HAS_SYN;
                }
                rsm->r_start = seq_out;
                rsm->r_end = rsm->r_start + len;
                rack_mark_in_gp_win(tp, rsm);
                rsm->r_dupack = 0;
                /*
                 * save off the mbuf location that
                 * sndmbuf_noadv returned (which is
                 * where we started copying from)..
                 */
                rsm->m = s_mb;
                rsm->soff = s_moff;
                /*
                 * Here we do add in the len of send, since its not yet
                 * reflected in in snduna <->snd_max
                 */
                rsm->r_fas = (ctf_flight_size(rack->rc_tp,
                                              rack->r_ctl.rc_sacked) +
                              (rsm->r_end - rsm->r_start));
                if ((rack->rc_initial_ss_comp == 0) &&
                    (rack->r_ctl.ss_hi_fs < rsm->r_fas)) {
                           rack->r_ctl.ss_hi_fs = rsm->r_fas;
                }
                /* rsm->m will be NULL if RACK_HAS_SYN or RACK_HAS_FIN is set */
                if (rsm->m) {
                        if (rsm->m->m_len <= rsm->soff) {
                                /*
                                 * XXXrrs Question, will this happen?
                                 *
                                 * If sbsndptr is set at the correct place
                                 * then s_moff should always be somewhere
                                 * within rsm->m. But if the sbsndptr was
                                 * off then that won't be true. If it occurs
                                 * we need to walkout to the correct location.
                                 */
                                struct mbuf *lm;

                                lm = rsm->m;
                                while (lm->m_len <= rsm->soff) {
                                        rsm->soff -= lm->m_len;
                                        lm = lm->m_next;
                                        KASSERT(lm != NULL, ("%s rack:%p lm goes null orig_off:%u origmb:%p rsm->soff:%u",
                                                             __func__, rack, s_moff, s_mb, rsm->soff));
                                }
                                rsm->m = lm;
                        }
                        rsm->orig_m_len = rsm->m->m_len;
                        rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                } else {
                        rsm->orig_m_len = 0;
                        rsm->orig_t_space = 0;
                }
                rsm->r_bas = (uint8_t)((len + segsiz - 1) / segsiz);
                rack_log_retran_reason(rack, rsm, __LINE__, 0, 2);
                /* Log a new rsm */
                rack_log_map_chg(tp, rack, NULL, rsm, NULL, MAP_NEW, 0, __LINE__);
#ifndef INVARIANTS
                (void)tqhash_insert(rack->r_ctl.tqh, rsm);
#else
                if ((insret = tqhash_insert(rack->r_ctl.tqh, rsm)) != 0) {
                        panic("Insert in tailq_hash of %p fails ret:%d rack:%p rsm:%p",
                              nrsm, insret, rack, rsm);
                }
#endif
                TAILQ_INSERT_TAIL(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                rsm->r_in_tmap = 1;
                if (rsm->r_flags & RACK_IS_PCM) {
                        rack->r_ctl.pcm_i.send_time = cts;
                        rack->r_ctl.pcm_i.eseq = rsm->r_end;
                        /* First time through we set the start too */
                        if (rack->pcm_in_progress == 0)
                                rack->r_ctl.pcm_i.sseq = rsm->r_start;
                }
                /*
                 * Special case detection, is there just a single
                 * packet outstanding when we are not in recovery?
                 *
                 * If this is true mark it so.
                 */
                if ((IN_FASTRECOVERY(tp->t_flags) == 0) &&
                    (ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked) == ctf_fixed_maxseg(tp))) {
                        struct rack_sendmap *prsm;

                        prsm = tqhash_prev(rack->r_ctl.tqh, rsm);
                        if (prsm)
                                prsm->r_one_out_nr = 1;
                }
                return;
        }
        /*
         * If we reach here its a retransmission and we need to find it.
         */
more:
        if (hintrsm && (hintrsm->r_start == seq_out)) {
                rsm = hintrsm;
                hintrsm = NULL;
        } else {
                /* No hints sorry */
                rsm = NULL;
        }
        if ((rsm) && (rsm->r_start == seq_out)) {
                seq_out = rack_update_entry(tp, rack, rsm, cts, &len, add_flag, segsiz);
                if (len == 0) {
                        return;
                } else {
                        goto more;
                }
        }
        /* Ok it was not the last pointer go through it the hard way. */
refind:
        rsm = tqhash_find(rack->r_ctl.tqh, seq_out);
        if (rsm) {
                if (rsm->r_start == seq_out) {
                        seq_out = rack_update_entry(tp, rack, rsm, cts, &len, add_flag, segsiz);
                        if (len == 0) {
                                return;
                        } else {
                                goto refind;
                        }
                }
                if (SEQ_GEQ(seq_out, rsm->r_start) && SEQ_LT(seq_out, rsm->r_end)) {
                        /* Transmitted within this piece */
                        /*
                         * Ok we must split off the front and then let the
                         * update do the rest
                         */
                        nrsm = rack_alloc_full_limit(rack);
                        if (nrsm == NULL) {
                                rack_update_rsm(tp, rack, rsm, cts, add_flag, segsiz);
                                return;
                        }
                        /*
                         * copy rsm to nrsm and then trim the front of rsm
                         * to not include this part.
                         */
                        rack_clone_rsm(rack, nrsm, rsm, seq_out);
                        rack_log_map_chg(tp, rack, NULL, rsm, nrsm, MAP_SPLIT, 0, __LINE__);
#ifndef INVARIANTS
                        (void)tqhash_insert(rack->r_ctl.tqh, nrsm);
#else
                        if ((insret = tqhash_insert(rack->r_ctl.tqh, nrsm)) != 0) {
                                panic("Insert in tailq_hash of %p fails ret:%d rack:%p rsm:%p",
                                      nrsm, insret, rack, rsm);
                        }
#endif
                        if (rsm->r_in_tmap) {
                                TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, rsm, nrsm, r_tnext);
                                nrsm->r_in_tmap = 1;
                        }
                        rsm->r_flags &= (~RACK_HAS_FIN);
                        seq_out = rack_update_entry(tp, rack, nrsm, cts, &len, add_flag, segsiz);
                        if (len == 0) {
                                return;
                        } else if (len > 0)
                                goto refind;
                }
        }
        /*
         * Hmm not found in map did they retransmit both old and on into the
         * new?
         */
        if (seq_out == tp->snd_max) {
                goto again;
        } else if (SEQ_LT(seq_out, tp->snd_max)) {
#ifdef INVARIANTS
                printf("seq_out:%u len:%d snd_una:%u snd_max:%u -- but rsm not found?\n",
                       seq_out, len, tp->snd_una, tp->snd_max);
                printf("Starting Dump of all rack entries\n");
                TQHASH_FOREACH(rsm, rack->r_ctl.tqh)  {
                        printf("rsm:%p start:%u end:%u\n",
                               rsm, rsm->r_start, rsm->r_end);
                }
                printf("Dump complete\n");
                panic("seq_out not found rack:%p tp:%p",
                      rack, tp);
#endif
        } else {
#ifdef INVARIANTS
                /*
                 * Hmm beyond sndmax? (only if we are using the new rtt-pack
                 * flag)
                 */
                panic("seq_out:%u(%d) is beyond snd_max:%u tp:%p",
                      seq_out, len, tp->snd_max, tp);
#endif
        }
}

/*
 * Record one of the RTT updates from an ack into
 * our sample structure.
 */

static void
tcp_rack_xmit_timer(struct tcp_rack *rack, int32_t rtt, uint32_t len, uint32_t us_rtt,
                    int confidence, struct rack_sendmap *rsm, uint16_t rtrcnt)
{
        if ((rack->r_ctl.rack_rs.rs_flags & RACK_RTT_EMPTY) ||
            (rack->r_ctl.rack_rs.rs_rtt_lowest > rtt)) {
                rack->r_ctl.rack_rs.rs_rtt_lowest = rtt;
        }
        if ((rack->r_ctl.rack_rs.rs_flags & RACK_RTT_EMPTY) ||
            (rack->r_ctl.rack_rs.rs_rtt_highest < rtt)) {
                rack->r_ctl.rack_rs.rs_rtt_highest = rtt;
        }
        if (rack->rc_tp->t_flags & TF_GPUTINPROG) {
            if (us_rtt < rack->r_ctl.rc_gp_lowrtt)
                rack->r_ctl.rc_gp_lowrtt = us_rtt;
            if (rack->rc_tp->snd_wnd > rack->r_ctl.rc_gp_high_rwnd)
                    rack->r_ctl.rc_gp_high_rwnd = rack->rc_tp->snd_wnd;
        }
        if ((confidence == 1) &&
            ((rsm == NULL) ||
             (rsm->r_just_ret) ||
             (rsm->r_one_out_nr &&
              len < (ctf_fixed_maxseg(rack->rc_tp) * 2)))) {
                /*
                 * If the rsm had a just return
                 * hit it then we can't trust the
                 * rtt measurement for buffer deterimination
                 * Note that a confidence of 2, indicates
                 * SACK'd which overrides the r_just_ret or
                 * the r_one_out_nr. If it was a CUM-ACK and
                 * we had only two outstanding, but get an
                 * ack for only 1. Then that also lowers our
                 * confidence.
                 */
                confidence = 0;
        }
        if ((rack->r_ctl.rack_rs.rs_flags & RACK_RTT_EMPTY) ||
            (rack->r_ctl.rack_rs.rs_us_rtt > us_rtt)) {
                if (rack->r_ctl.rack_rs.confidence == 0) {
                        /*
                         * We take anything with no current confidence
                         * saved.
                         */
                        rack->r_ctl.rack_rs.rs_us_rtt = us_rtt;
                        rack->r_ctl.rack_rs.confidence = confidence;
                        rack->r_ctl.rack_rs.rs_us_rtrcnt = rtrcnt;
                } else if (confidence != 0) {
                        /*
                         * Once we have a confident number,
                         * we can update it with a smaller
                         * value since this confident number
                         * may include the DSACK time until
                         * the next segment (the second one) arrived.
                         */
                        rack->r_ctl.rack_rs.rs_us_rtt = us_rtt;
                        rack->r_ctl.rack_rs.confidence = confidence;
                        rack->r_ctl.rack_rs.rs_us_rtrcnt = rtrcnt;
                }
        }
        rack_log_rtt_upd(rack->rc_tp, rack, us_rtt, len, rsm, confidence);
        rack->r_ctl.rack_rs.rs_flags = RACK_RTT_VALID;
        rack->r_ctl.rack_rs.rs_rtt_tot += rtt;
        rack->r_ctl.rack_rs.rs_rtt_cnt++;
}

/*
 * Collect new round-trip time estimate
 * and update averages and current timeout.
 */
static void
tcp_rack_xmit_timer_commit(struct tcp_rack *rack, struct tcpcb *tp)
{
        int32_t delta;
        int32_t rtt;

        if (rack->r_ctl.rack_rs.rs_flags & RACK_RTT_EMPTY)
                /* No valid sample */
                return;
        if (rack->r_ctl.rc_rate_sample_method == USE_RTT_LOW) {
                /* We are to use the lowest RTT seen in a single ack */
                rtt = rack->r_ctl.rack_rs.rs_rtt_lowest;
        } else if (rack->r_ctl.rc_rate_sample_method == USE_RTT_HIGH) {
                /* We are to use the highest RTT seen in a single ack */
                rtt = rack->r_ctl.rack_rs.rs_rtt_highest;
        } else if (rack->r_ctl.rc_rate_sample_method == USE_RTT_AVG) {
                /* We are to use the average RTT seen in a single ack */
                rtt = (int32_t)(rack->r_ctl.rack_rs.rs_rtt_tot /
                                (uint64_t)rack->r_ctl.rack_rs.rs_rtt_cnt);
        } else {
#ifdef INVARIANTS
                panic("Unknown rtt variant %d", rack->r_ctl.rc_rate_sample_method);
#endif
                return;
        }
        if (rtt == 0)
                rtt = 1;
        if (rack->rc_gp_rtt_set == 0) {
                /*
                 * With no RTT we have to accept
                 * even one we are not confident of.
                 */
                rack->r_ctl.rc_gp_srtt = rack->r_ctl.rack_rs.rs_us_rtt;
                rack->rc_gp_rtt_set = 1;
        } else if (rack->r_ctl.rack_rs.confidence) {
                /* update the running gp srtt */
                rack->r_ctl.rc_gp_srtt -= (rack->r_ctl.rc_gp_srtt/8);
                rack->r_ctl.rc_gp_srtt += rack->r_ctl.rack_rs.rs_us_rtt / 8;
        }
        if (rack->r_ctl.rack_rs.confidence) {
                /*
                 * record the low and high for highly buffered path computation,
                 * we only do this if we are confident (not a retransmission).
                 */
                if (rack->r_ctl.rc_highest_us_rtt < rack->r_ctl.rack_rs.rs_us_rtt) {
                        rack->r_ctl.rc_highest_us_rtt = rack->r_ctl.rack_rs.rs_us_rtt;
                }
                if (rack->rc_highly_buffered == 0) {
                        /*
                         * Currently once we declare a path has
                         * highly buffered there is no going
                         * back, which may be a problem...
                         */
                        if ((rack->r_ctl.rc_highest_us_rtt / rack->r_ctl.rc_lowest_us_rtt) > rack_hbp_thresh) {
                                rack_log_rtt_shrinks(rack, rack->r_ctl.rack_rs.rs_us_rtt,
                                                     rack->r_ctl.rc_highest_us_rtt,
                                                     rack->r_ctl.rc_lowest_us_rtt,
                                                     RACK_RTTS_SEEHBP);
                                rack->rc_highly_buffered = 1;
                        }
                }
        }
        if ((rack->r_ctl.rack_rs.confidence) ||
            (rack->r_ctl.rack_rs.rs_us_rtrcnt == 1)) {
                /*
                 * If we are highly confident of it <or> it was
                 * never retransmitted we accept it as the last us_rtt.
                 */
                rack->r_ctl.rc_last_us_rtt = rack->r_ctl.rack_rs.rs_us_rtt;
                /* The lowest rtt can be set if its was not retransmited */
                if (rack->r_ctl.rc_lowest_us_rtt > rack->r_ctl.rack_rs.rs_us_rtt) {
                        rack->r_ctl.rc_lowest_us_rtt = rack->r_ctl.rack_rs.rs_us_rtt;
                        if (rack->r_ctl.rc_lowest_us_rtt == 0)
                                rack->r_ctl.rc_lowest_us_rtt = 1;
                }
        }
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (tp->t_srtt != 0) {
                /*
                 * We keep a simple srtt in microseconds, like our rtt
                 * measurement. We don't need to do any tricks with shifting
                 * etc. Instead we just add in 1/8th of the new measurement
                 * and subtract out 1/8 of the old srtt. We do the same with
                 * the variance after finding the absolute value of the
                 * difference between this sample and the current srtt.
                 */
                delta = tp->t_srtt - rtt;
                /* Take off 1/8th of the current sRTT */
                tp->t_srtt -= (tp->t_srtt >> 3);
                /* Add in 1/8th of the new RTT just measured */
                tp->t_srtt += (rtt >> 3);
                if (tp->t_srtt <= 0)
                        tp->t_srtt = 1;
                /* Now lets make the absolute value of the variance */
                if (delta < 0)
                        delta = -delta;
                /* Subtract out 1/8th */
                tp->t_rttvar -= (tp->t_rttvar >> 3);
                /* Add in 1/8th of the new variance we just saw */
                tp->t_rttvar += (delta >> 3);
                if (tp->t_rttvar <= 0)
                        tp->t_rttvar = 1;
        } else {
                /*
                 * No rtt measurement yet - use the unsmoothed rtt. Set the
                 * variance to half the rtt (so our first retransmit happens
                 * at 3*rtt).
                 */
                tp->t_srtt = rtt;
                tp->t_rttvar = rtt >> 1;
        }
        rack->rc_srtt_measure_made = 1;
        KMOD_TCPSTAT_INC(tcps_rttupdated);
        if (tp->t_rttupdated < UCHAR_MAX)
                tp->t_rttupdated++;
#ifdef STATS
        if (rack_stats_gets_ms_rtt == 0) {
                /* Send in the microsecond rtt used for rxt timeout purposes */
                stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_RTT, imax(0, rtt));
        } else if (rack_stats_gets_ms_rtt == 1) {
                /* Send in the millisecond rtt used for rxt timeout purposes */
                int32_t ms_rtt;

                /* Round up */
                ms_rtt = (rtt + HPTS_USEC_IN_MSEC - 1) / HPTS_USEC_IN_MSEC;
                stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_RTT, imax(0, ms_rtt));
        } else if (rack_stats_gets_ms_rtt == 2) {
                /* Send in the millisecond rtt has close to the path RTT as we can get  */
                int32_t ms_rtt;

                /* Round up */
                ms_rtt = (rack->r_ctl.rack_rs.rs_us_rtt + HPTS_USEC_IN_MSEC - 1) / HPTS_USEC_IN_MSEC;
                stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_RTT, imax(0, ms_rtt));
        }  else {
                /* Send in the microsecond rtt has close to the path RTT as we can get  */
                stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_RTT, imax(0, rack->r_ctl.rack_rs.rs_us_rtt));
        }
        stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_PATHRTT, imax(0, rack->r_ctl.rack_rs.rs_us_rtt));
#endif
        rack->r_ctl.last_rcv_tstmp_for_rtt = tcp_tv_to_msec(&rack->r_ctl.act_rcv_time);
        /*
         * the retransmit should happen at rtt + 4 * rttvar. Because of the
         * way we do the smoothing, srtt and rttvar will each average +1/2
         * tick of bias.  When we compute the retransmit timer, we want 1/2
         * tick of rounding and 1 extra tick because of +-1/2 tick
         * uncertainty in the firing of the timer.  The bias will give us
         * exactly the 1.5 tick we need.  But, because the bias is
         * statistical, we have to test that we don't drop below the minimum
         * feasible timer (which is 2 ticks).
         */
        tp->t_rxtshift = 0;
        RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                      max(rack_rto_min, rtt + 2), rack_rto_max, rack->r_ctl.timer_slop);
        rack_log_rtt_sample(rack, rtt);
        tp->t_softerror = 0;
}


static void
rack_apply_updated_usrtt(struct tcp_rack *rack, uint32_t us_rtt, uint32_t us_cts)
{
        /*
         * Apply to filter the inbound us-rtt at us_cts.
         */
        uint32_t old_rtt;

        old_rtt = get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt);
        apply_filter_min_small(&rack->r_ctl.rc_gp_min_rtt,
                               us_rtt, us_cts);
        if (old_rtt > us_rtt) {
                /* We just hit a new lower rtt time */
                rack_log_rtt_shrinks(rack,  us_cts,  old_rtt,
                                     __LINE__, RACK_RTTS_NEWRTT);
                /*
                 * Only count it if its lower than what we saw within our
                 * calculated range.
                 */
                if ((old_rtt - us_rtt) > rack_min_rtt_movement) {
                        if (rack_probertt_lower_within &&
                            rack->rc_gp_dyn_mul &&
                            (rack->use_fixed_rate == 0) &&
                            (rack->rc_always_pace)) {
                                /*
                                 * We are seeing a new lower rtt very close
                                 * to the time that we would have entered probe-rtt.
                                 * This is probably due to the fact that a peer flow
                                 * has entered probe-rtt. Lets go in now too.
                                 */
                                uint32_t val;

                                val = rack_probertt_lower_within * rack_time_between_probertt;
                                val /= 100;
                                if ((rack->in_probe_rtt == 0) &&
                                    (rack->rc_skip_timely == 0) &&
                                    ((us_cts - rack->r_ctl.rc_lower_rtt_us_cts) >= (rack_time_between_probertt - val))) {
                                        rack_enter_probertt(rack, us_cts);
                                }
                        }
                        rack->r_ctl.rc_lower_rtt_us_cts = us_cts;
                }
        }
}

static int
rack_update_rtt(struct tcpcb *tp, struct tcp_rack *rack,
    struct rack_sendmap *rsm, struct tcpopt *to, uint32_t cts, int32_t ack_type, tcp_seq th_ack)
{
        uint32_t us_rtt;
        int32_t i, all;
        uint32_t t, len_acked;

        if ((rsm->r_flags & RACK_ACKED) ||
            (rsm->r_flags & RACK_WAS_ACKED))
                /* Already done */
                return (0);
        if (rsm->r_no_rtt_allowed) {
                /* Not allowed */
                return (0);
        }
        if (ack_type == CUM_ACKED) {
                if (SEQ_GT(th_ack, rsm->r_end)) {
                        len_acked = rsm->r_end - rsm->r_start;
                        all = 1;
                } else {
                        len_acked = th_ack - rsm->r_start;
                        all = 0;
                }
        } else {
                len_acked = rsm->r_end - rsm->r_start;
                all = 0;
        }
        if (rsm->r_rtr_cnt == 1) {

                t = cts - (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)];
                if ((int)t <= 0)
                        t = 1;
                if (!tp->t_rttlow || tp->t_rttlow > t)
                        tp->t_rttlow = t;
                if (!rack->r_ctl.rc_rack_min_rtt ||
                    SEQ_LT(t, rack->r_ctl.rc_rack_min_rtt)) {
                        rack->r_ctl.rc_rack_min_rtt = t;
                        if (rack->r_ctl.rc_rack_min_rtt == 0) {
                                rack->r_ctl.rc_rack_min_rtt = 1;
                        }
                }
                if (TSTMP_GT(tcp_tv_to_usec(&rack->r_ctl.act_rcv_time), rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)]))
                        us_rtt = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time) - (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)];
                else
                        us_rtt = tcp_get_usecs(NULL) - (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)];
                if (us_rtt == 0)
                        us_rtt = 1;
                if (CC_ALGO(tp)->rttsample != NULL) {
                        /* Kick the RTT to the CC */
                        CC_ALGO(tp)->rttsample(&tp->t_ccv, us_rtt, 1, rsm->r_fas);
                }
                rack_apply_updated_usrtt(rack, us_rtt, tcp_tv_to_usec(&rack->r_ctl.act_rcv_time));
                if (ack_type == SACKED) {
                        rack_log_rtt_sample_calc(rack, t, (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)], cts, 1);
                        tcp_rack_xmit_timer(rack, t + 1, len_acked, us_rtt, 2 , rsm, rsm->r_rtr_cnt);
                } else {
                        /*
                         * We need to setup what our confidence
                         * is in this ack.
                         *
                         * If the rsm was app limited and it is
                         * less than a mss in length (the end
                         * of the send) then we have a gap. If we
                         * were app limited but say we were sending
                         * multiple MSS's then we are more confident
                         * int it.
                         *
                         * When we are not app-limited then we see if
                         * the rsm is being included in the current
                         * measurement, we tell this by the app_limited_needs_set
                         * flag.
                         *
                         * Note that being cwnd blocked is not applimited
                         * as well as the pacing delay between packets which
                         * are sending only 1 or 2 MSS's also will show up
                         * in the RTT. We probably need to examine this algorithm
                         * a bit more and enhance it to account for the delay
                         * between rsm's. We could do that by saving off the
                         * pacing delay of each rsm (in an rsm) and then
                         * factoring that in somehow though for now I am
                         * not sure how :)
                         */
                        int calc_conf = 0;

                        if (rsm->r_flags & RACK_APP_LIMITED) {
                                if (all && (len_acked <= ctf_fixed_maxseg(tp)))
                                        calc_conf = 0;
                                else
                                        calc_conf = 1;
                        } else if (rack->app_limited_needs_set == 0) {
                                calc_conf = 1;
                        } else {
                                calc_conf = 0;
                        }
                        rack_log_rtt_sample_calc(rack, t, (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)], cts, 2);
                        tcp_rack_xmit_timer(rack, t + 1, len_acked, us_rtt,
                                            calc_conf, rsm, rsm->r_rtr_cnt);
                }
                if ((rsm->r_flags & RACK_TLP) &&
                    (!IN_FASTRECOVERY(tp->t_flags))) {
                        /* Segment was a TLP and our retrans matched */
                        if (rack->r_ctl.rc_tlp_cwnd_reduce) {
                                rack_cong_signal(tp, CC_NDUPACK, th_ack, __LINE__);
                        }
                }
                if ((rack->r_ctl.rc_rack_tmit_time == 0) ||
                    (SEQ_LT(rack->r_ctl.rc_rack_tmit_time,
                            (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)]))) {
                        /* New more recent rack_tmit_time */
                        rack->r_ctl.rc_rack_tmit_time = (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)];
                        if (rack->r_ctl.rc_rack_tmit_time == 0)
                                rack->r_ctl.rc_rack_tmit_time = 1;
                        rack->rc_rack_rtt = t;
                }
                return (1);
        }
        /*
         * We clear the soft/rxtshift since we got an ack.
         * There is no assurance we will call the commit() function
         * so we need to clear these to avoid incorrect handling.
         */
        tp->t_rxtshift = 0;
        RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                      rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
        tp->t_softerror = 0;
        if (to && (to->to_flags & TOF_TS) &&
            (ack_type == CUM_ACKED) &&
            (to->to_tsecr) &&
            ((rsm->r_flags & RACK_OVERMAX) == 0)) {
                /*
                 * Now which timestamp does it match? In this block the ACK
                 * must be coming from a previous transmission.
                 */
                for (i = 0; i < rsm->r_rtr_cnt; i++) {
                        if (rack_ts_to_msec(rsm->r_tim_lastsent[i]) == to->to_tsecr) {
                                t = cts - (uint32_t)rsm->r_tim_lastsent[i];
                                if ((int)t <= 0)
                                        t = 1;
                                if (CC_ALGO(tp)->rttsample != NULL) {
                                        /*
                                         * Kick the RTT to the CC, here
                                         * we lie a bit in that we know the
                                         * retransmission is correct even though
                                         * we retransmitted. This is because
                                         * we match the timestamps.
                                         */
                                        if (TSTMP_GT(tcp_tv_to_usec(&rack->r_ctl.act_rcv_time), rsm->r_tim_lastsent[i]))
                                                us_rtt = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time) - (uint32_t)rsm->r_tim_lastsent[i];
                                        else
                                                us_rtt = tcp_get_usecs(NULL) - (uint32_t)rsm->r_tim_lastsent[i];
                                        CC_ALGO(tp)->rttsample(&tp->t_ccv, us_rtt, 1, rsm->r_fas);
                                }
                                if ((i + 1) < rsm->r_rtr_cnt) {
                                        /*
                                         * The peer ack'd from our previous
                                         * transmission. We have a spurious
                                         * retransmission and thus we dont
                                         * want to update our rack_rtt.
                                         *
                                         * Hmm should there be a CC revert here?
                                         *
                                         */
                                        return (0);
                                }
                                if (!tp->t_rttlow || tp->t_rttlow > t)
                                        tp->t_rttlow = t;
                                if (!rack->r_ctl.rc_rack_min_rtt || SEQ_LT(t, rack->r_ctl.rc_rack_min_rtt)) {
                                        rack->r_ctl.rc_rack_min_rtt = t;
                                        if (rack->r_ctl.rc_rack_min_rtt == 0) {
                                                rack->r_ctl.rc_rack_min_rtt = 1;
                                        }
                                }
                                if ((rack->r_ctl.rc_rack_tmit_time == 0) ||
                                    (SEQ_LT(rack->r_ctl.rc_rack_tmit_time,
                                            (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)]))) {
                                        /* New more recent rack_tmit_time */
                                        rack->r_ctl.rc_rack_tmit_time = (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)];
                                        if (rack->r_ctl.rc_rack_tmit_time == 0)
                                                rack->r_ctl.rc_rack_tmit_time = 1;
                                        rack->rc_rack_rtt = t;
                                }
                                rack_log_rtt_sample_calc(rack, t, (uint32_t)rsm->r_tim_lastsent[i], cts, 3);
                                tcp_rack_xmit_timer(rack, t + 1, len_acked, t, 0, rsm,
                                                    rsm->r_rtr_cnt);
                                return (1);
                        }
                }
                /* If we are logging log out the sendmap */
                if (tcp_bblogging_on(rack->rc_tp)) {
                        for (i = 0; i < rsm->r_rtr_cnt; i++) {
                                rack_log_rtt_sendmap(rack, i, rsm->r_tim_lastsent[i], to->to_tsecr);
                        }
                }
                goto ts_not_found;
        } else {
                /*
                 * Ok its a SACK block that we retransmitted. or a windows
                 * machine without timestamps. We can tell nothing from the
                 * time-stamp since its not there or the time the peer last
                 * received a segment that moved forward its cum-ack point.
                 */
ts_not_found:
                i = rsm->r_rtr_cnt - 1;
                t = cts - (uint32_t)rsm->r_tim_lastsent[i];
                if ((int)t <= 0)
                        t = 1;
                if (rack->r_ctl.rc_rack_min_rtt && SEQ_LT(t, rack->r_ctl.rc_rack_min_rtt)) {
                        /*
                         * We retransmitted and the ack came back in less
                         * than the smallest rtt we have observed. We most
                         * likely did an improper retransmit as outlined in
                         * 6.2 Step 2 point 2 in the rack-draft so we
                         * don't want to update our rack_rtt. We in
                         * theory (in future) might want to think about reverting our
                         * cwnd state but we won't for now.
                         */
                        return (0);
                } else if (rack->r_ctl.rc_rack_min_rtt) {
                        /*
                         * We retransmitted it and the retransmit did the
                         * job.
                         */
                        if (!rack->r_ctl.rc_rack_min_rtt ||
                            SEQ_LT(t, rack->r_ctl.rc_rack_min_rtt)) {
                                rack->r_ctl.rc_rack_min_rtt = t;
                                if (rack->r_ctl.rc_rack_min_rtt == 0) {
                                        rack->r_ctl.rc_rack_min_rtt = 1;
                                }
                        }
                        if ((rack->r_ctl.rc_rack_tmit_time == 0) ||
                            (SEQ_LT(rack->r_ctl.rc_rack_tmit_time,
                                    (uint32_t)rsm->r_tim_lastsent[i]))) {
                                /* New more recent rack_tmit_time */
                                rack->r_ctl.rc_rack_tmit_time = (uint32_t)rsm->r_tim_lastsent[i];
                                if (rack->r_ctl.rc_rack_tmit_time == 0)
                                        rack->r_ctl.rc_rack_tmit_time = 1;
                                rack->rc_rack_rtt = t;
                        }
                        return (1);
                }
        }
        return (0);
}

/*
 * Mark the SACK_PASSED flag on all entries prior to rsm send wise.
 */
static void
rack_log_sack_passed(struct tcpcb *tp,
    struct tcp_rack *rack, struct rack_sendmap *rsm, uint32_t cts, int line)
{
        struct rack_sendmap *nrsm;
        uint32_t thresh;

        /* Get our rxt threshold for lost consideration */
        thresh = rack_calc_thresh_rack(rack, rack_grab_rtt(tp, rack), cts, __LINE__, 0);
        /* Now start looking at rsm's */
        nrsm = rsm;
        TAILQ_FOREACH_REVERSE_FROM(nrsm, &rack->r_ctl.rc_tmap,
            rack_head, r_tnext) {
                if (nrsm == rsm) {
                        /* Skip original segment he is acked */
                        continue;
                }
                if (nrsm->r_flags & RACK_ACKED) {
                        /*
                         * Skip ack'd segments, though we
                         * should not see these, since tmap
                         * should not have ack'd segments.
                         */
                        continue;
                }
                if (nrsm->r_flags & RACK_RWND_COLLAPSED) {
                        /*
                         * If the peer dropped the rwnd on
                         * these then we don't worry about them.
                         */
                        continue;
                }
                /* Check lost state */
                if ((nrsm->r_flags & RACK_WAS_LOST) == 0) {
                        uint32_t exp;

                        exp = ((uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)]) + thresh;
                        if (TSTMP_LT(exp, cts) || (exp == cts)) {
                                /* We consider it lost */
                                nrsm->r_flags |= RACK_WAS_LOST;
                                rack->r_ctl.rc_considered_lost += nrsm->r_end - nrsm->r_start;
                        }
                }
                if (nrsm->r_flags & RACK_SACK_PASSED) {
                        /*
                         * We found one that is already marked
                         * passed, we have been here before and
                         * so all others below this are marked.
                         */
                        break;
                }
                rack_log_dsack_event(rack, 12, __LINE__, nrsm->r_start, nrsm->r_end);
                nrsm->r_flags |= RACK_SACK_PASSED;
                nrsm->r_flags &= ~RACK_WAS_SACKPASS;
        }
}

static void
rack_need_set_test(struct tcpcb *tp,
                   struct tcp_rack *rack,
                   struct rack_sendmap *rsm,
                   tcp_seq th_ack,
                   int line,
                   int use_which)
{
        struct rack_sendmap *s_rsm;

        if ((tp->t_flags & TF_GPUTINPROG) &&
            SEQ_GEQ(rsm->r_end, tp->gput_seq)) {
                /*
                 * We were app limited, and this ack
                 * butts up or goes beyond the point where we want
                 * to start our next measurement. We need
                 * to record the new gput_ts as here and
                 * possibly update the start sequence.
                 */
                uint32_t seq, ts;

                if (rsm->r_rtr_cnt > 1) {
                        /*
                         * This is a retransmit, can we
                         * really make any assessment at this
                         * point?  We are not really sure of
                         * the timestamp, is it this or the
                         * previous transmission?
                         *
                         * Lets wait for something better that
                         * is not retransmitted.
                         */
                        return;
                }
                seq = tp->gput_seq;
                ts = tp->gput_ts;
                rack->app_limited_needs_set = 0;
                tp->gput_ts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
                /* Do we start at a new end? */
                if ((use_which == RACK_USE_BEG) &&
                    SEQ_GEQ(rsm->r_start, tp->gput_seq)) {
                        /*
                         * When we get an ACK that just eats
                         * up some of the rsm, we set RACK_USE_BEG
                         * since whats at r_start (i.e. th_ack)
                         * is left unacked and thats where the
                         * measurement now starts.
                         */
                        tp->gput_seq = rsm->r_start;
                }
                if ((use_which == RACK_USE_END) &&
                    SEQ_GEQ(rsm->r_end, tp->gput_seq)) {
                        /*
                         * We use the end when the cumack
                         * is moving forward and completely
                         * deleting the rsm passed so basically
                         * r_end holds th_ack.
                         *
                         * For SACK's we also want to use the end
                         * since this piece just got sacked and
                         * we want to target anything after that
                         * in our measurement.
                         */
                        tp->gput_seq = rsm->r_end;
                }
                if (use_which == RACK_USE_END_OR_THACK) {
                        /*
                         * special case for ack moving forward,
                         * not a sack, we need to move all the
                         * way up to where this ack cum-ack moves
                         * to.
                         */
                        if (SEQ_GT(th_ack, rsm->r_end))
                                tp->gput_seq = th_ack;
                        else
                                tp->gput_seq = rsm->r_end;
                }
                if (SEQ_LT(tp->gput_seq, tp->snd_max))
                        s_rsm = tqhash_find(rack->r_ctl.tqh, tp->gput_seq);
                else
                        s_rsm = NULL;
                /*
                 * Pick up the correct send time if we can the rsm passed in
                 * may be equal to s_rsm if the RACK_USE_BEG was set. For the other
                 * two cases (RACK_USE_THACK or RACK_USE_END) most likely we will
                 * find a different seq i.e. the next send up.
                 *
                 * If that has not been sent, s_rsm will be NULL and we must
                 * arrange it so this function will get called again by setting
                 * app_limited_needs_set.
                 */
                if (s_rsm)
                        rack->r_ctl.rc_gp_output_ts = s_rsm->r_tim_lastsent[0];
                else {
                        /* If we hit here we have to have *not* sent tp->gput_seq */
                        rack->r_ctl.rc_gp_output_ts = rsm->r_tim_lastsent[0];
                        /* Set it up so we will go through here again */
                        rack->app_limited_needs_set = 1;
                }
                if (SEQ_GT(tp->gput_seq, tp->gput_ack)) {
                        /*
                         * We moved beyond this guy's range, re-calculate
                         * the new end point.
                         */
                        if (rack->rc_gp_filled == 0) {
                                tp->gput_ack = tp->gput_seq + max(rc_init_window(rack), (MIN_GP_WIN * ctf_fixed_maxseg(tp)));
                        } else {
                                tp->gput_ack = tp->gput_seq + rack_get_measure_window(tp, rack);
                        }
                }
                /*
                 * We are moving the goal post, we may be able to clear the
                 * measure_saw_probe_rtt flag.
                 */
                if ((rack->in_probe_rtt == 0) &&
                    (rack->measure_saw_probe_rtt) &&
                    (SEQ_GEQ(tp->gput_seq, rack->r_ctl.rc_probertt_sndmax_atexit)))
                        rack->measure_saw_probe_rtt = 0;
                rack_log_pacing_delay_calc(rack, ts, tp->gput_ts,
                                           seq, tp->gput_seq,
                                           (((uint64_t)rack->r_ctl.rc_app_limited_cnt << 32) |
                                            (uint64_t)rack->r_ctl.rc_gp_output_ts),
                                           5, line, NULL, 0);
                if (rack->rc_gp_filled &&
                    ((tp->gput_ack - tp->gput_seq) <
                     max(rc_init_window(rack), (MIN_GP_WIN *
                                                ctf_fixed_maxseg(tp))))) {
                        uint32_t ideal_amount;

                        ideal_amount = rack_get_measure_window(tp, rack);
                        if (ideal_amount > sbavail(&tptosocket(tp)->so_snd)) {
                                /*
                                 * There is no sense of continuing this measurement
                                 * because its too small to gain us anything we
                                 * trust. Skip it and that way we can start a new
                                 * measurement quicker.
                                 */
                                tp->t_flags &= ~TF_GPUTINPROG;
                                rack_log_pacing_delay_calc(rack, tp->gput_ack, tp->gput_seq,
                                                           0, 0,
                                                           (((uint64_t)rack->r_ctl.rc_app_limited_cnt << 32) |
                                                            (uint64_t)rack->r_ctl.rc_gp_output_ts),
                                                           6, __LINE__, NULL, 0);
                        } else {
                                /*
                                 * Reset the window further out.
                                 */
                                tp->gput_ack = tp->gput_seq + ideal_amount;
                        }
                }
                rack_tend_gp_marks(tp, rack);
                rack_log_gpset(rack, tp->gput_ack, 0, 0, line, 2, rsm);
        }
}

static inline int
is_rsm_inside_declared_tlp_block(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
        if (SEQ_LT(rsm->r_end, rack->r_ctl.last_tlp_acked_start)) {
                /* Behind our TLP definition or right at */
                return (0);
        }
        if (SEQ_GT(rsm->r_start, rack->r_ctl.last_tlp_acked_end)) {
                /* The start is beyond or right at our end of TLP definition */
                return (0);
        }
        /* It has to be a sub-part of the original TLP recorded */
        return (1);
}


static int
rack_check_reorder_ack(struct tcpcb *tp, struct tcp_rack *rack, struct rack_sendmap *rsm, int the_end, uint32_t cts, int can_exit_recovery, int line)
{
        if ((rack_rtt_divisor > 0) &&
            (rsm->r_rtr_cnt == 2) &&
            IN_RECOVERY(tp->t_flags) &&
            (rsm->r_flags & RACK_WAS_SACKPASS)){
                uint32_t fractional, snt_to_ack;

                fractional = (tp->t_srtt / rack_rtt_divisor);
                if (fractional == 0)
                        fractional = 1;
                snt_to_ack = cts - (uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)];
                if (snt_to_ack <= fractional) {
                        rack->r_ctl.rc_reorder_ts = cts;
                        KASSERT((rack->r_ctl.recovery_rxt_cnt >= (the_end - rsm->r_start)),
                                ("rsm:%p rack:%p recovery_rxt_cnt would go negative recovery_rxt_cnt:%u sub:%u", rsm,  rack, rack->r_ctl.recovery_rxt_cnt, (the_end - rsm->r_start)));
                        rack->r_ctl.recovery_rxt_cnt -= (the_end - rsm->r_start);
                        rack_log_to_prr(rack, 18, rack->r_ctl.recovery_rxt_cnt, line);
                        if (can_exit_recovery && (rack->r_ctl.recovery_rxt_cnt == 0)) {
                                tp->snd_ssthresh = rack->r_ctl.rc_ssthresh_at_erec;
                                rack_exit_recovery(tp, rack, 4);
                                rack->r_might_revert = 0;
                                rack->r_ctl.retran_during_recovery = 0;
                                rack_log_to_prr(rack, 17, snt_to_ack, line);
                        }
                        return (1);
                }
        }
        return (0);
}

static uint32_t
rack_proc_sack_blk(struct tcpcb *tp, struct tcp_rack *rack, struct sackblk *sack,
                   struct tcpopt *to, struct rack_sendmap **prsm, uint32_t cts,
                   uint32_t segsiz)
{
        uint32_t start, end, changed = 0;
        struct rack_sendmap stack_map;
        struct rack_sendmap *rsm, *nrsm, *prev, *next;
        int insret __diagused;
        int32_t used_ref = 1;
        int can_use_hookery = 0;
        int prohibit_marking = 0;

        start = sack->start;
        end = sack->end;
        rsm = *prsm;

do_rest_ofb:
        if ((rsm == NULL) ||
            (SEQ_LT(end, rsm->r_start)) ||
            (SEQ_GEQ(start, rsm->r_end)) ||
            (SEQ_LT(start, rsm->r_start))) {
                /*
                 * We are not in the right spot,
                 * find the correct spot in the tree.
                 */
                used_ref = 0;
                rsm = tqhash_find(rack->r_ctl.tqh, start);
        }
        if (rsm == NULL) {
                /* TSNH */
                goto out;
        }
        /* Ok we have an ACK for some piece of this rsm */
        if (rsm->r_start != start) {
                if ((rsm->r_flags & RACK_ACKED) == 0) {
                        /*
                         * Before any splitting or hookery is
                         * done is it a TLP of interest i.e. rxt?
                         */
                        if ((rsm->r_flags & RACK_TLP) &&
                            (rsm->r_rtr_cnt > 1)) {
                                /*
                                 * We are splitting a rxt TLP, check
                                 * if we need to save off the start/end
                                 */
                                if (rack->rc_last_tlp_acked_set &&
                                    (is_rsm_inside_declared_tlp_block(rack, rsm))) {
                                        /*
                                         * We already turned this on since we are inside
                                         * the previous one was a partially sack now we
                                         * are getting another one (maybe all of it).
                                         *
                                         */
                                        rack_log_dsack_event(rack, 10, __LINE__, rsm->r_start, rsm->r_end);
                                        /*
                                         * Lets make sure we have all of it though.
                                         */
                                        if (SEQ_LT(rsm->r_start, rack->r_ctl.last_tlp_acked_start)) {
                                                rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                                     rack->r_ctl.last_tlp_acked_end);
                                        }
                                        if (SEQ_GT(rsm->r_end, rack->r_ctl.last_tlp_acked_end)) {
                                                rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                                     rack->r_ctl.last_tlp_acked_end);
                                        }
                                } else {
                                        rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                        rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                        rack->rc_last_tlp_past_cumack = 0;
                                        rack->rc_last_tlp_acked_set = 1;
                                        rack_log_dsack_event(rack, 8, __LINE__, rsm->r_start, rsm->r_end);
                                }
                        }
                        /**
                         * Need to split this in two pieces the before and after,
                         * the before remains in the map, the after must be
                         * added. In other words we have:
                         * rsm        |--------------|
                         * sackblk        |------->
                         * rsm will become
                         *     rsm    |---|
                         * and nrsm will be  the sacked piece
                         *     nrsm       |----------|
                         *
                         * But before we start down that path lets
                         * see if the sack spans over on top of
                         * the next guy and it is already sacked.
                         *
                         */
                        /*
                         * Hookery can only be used if the two entries
                         * are in the same bucket and neither one of
                         * them staddle the bucket line.
                         */
                        next = tqhash_next(rack->r_ctl.tqh, rsm);
                        if (next &&
                            (rsm->bindex == next->bindex) &&
                            ((rsm->r_flags & RACK_STRADDLE) == 0) &&
                            ((next->r_flags & RACK_STRADDLE) == 0) &&
                            ((rsm->r_flags & RACK_WAS_SACKPASS) == 0) &&
                            ((next->r_flags & RACK_WAS_SACKPASS) == 0) &&
                            ((rsm->r_flags & RACK_IS_PCM) == 0) &&
                            ((next->r_flags & RACK_IS_PCM) == 0) &&
                            (rsm->r_flags & RACK_IN_GP_WIN) &&
                            (next->r_flags & RACK_IN_GP_WIN))
                                can_use_hookery = 1;
                        else
                                can_use_hookery = 0;
                        if (next && can_use_hookery &&
                            (next->r_flags & RACK_ACKED) &&
                            SEQ_GEQ(end, next->r_start)) {
                                /**
                                 * So the next one is already acked, and
                                 * we can thus by hookery use our stack_map
                                 * to reflect the piece being sacked and
                                 * then adjust the two tree entries moving
                                 * the start and ends around. So we start like:
                                 *  rsm     |------------|             (not-acked)
                                 *  next                 |-----------| (acked)
                                 *  sackblk        |-------->
                                 *  We want to end like so:
                                 *  rsm     |------|                   (not-acked)
                                 *  next           |-----------------| (acked)
                                 *  nrsm           |-----|
                                 * Where nrsm is a temporary stack piece we
                                 * use to update all the gizmos.
                                 */
                                /* Copy up our fudge block */
                                nrsm = &stack_map;
                                memcpy(nrsm, rsm, sizeof(struct rack_sendmap));
                                /* Now adjust our tree blocks */
                                tqhash_update_end(rack->r_ctl.tqh, rsm, start);
                                next->r_start = start;
                                rsm->r_flags |= RACK_SHUFFLED;
                                next->r_flags |= RACK_SHUFFLED;
                                /* Now we must adjust back where next->m is */
                                rack_setup_offset_for_rsm(rack, rsm, next);
                                /*
                                 * Which timestamp do we keep? It is rather
                                 * important in GP measurements to have the
                                 * accurate end of the send window.
                                 *
                                 * We keep the largest value, which is the newest
                                 * send. We do this in case a segment that is
                                 * joined together and not part of a GP estimate
                                 * later gets expanded into the GP estimate.
                                 *
                                 * We prohibit the merging of unlike kinds i.e.
                                 * all pieces that are in the GP estimate can be
                                 * merged and all pieces that are not in a GP estimate
                                 * can be merged, but not disimilar pieces. Combine
                                 * this with taking the highest here and we should
                                 * be ok unless of course the client reneges. Then
                                 * all bets are off.
                                 */
                                if (next->r_tim_lastsent[(next->r_rtr_cnt-1)] <
                                    nrsm->r_tim_lastsent[(nrsm->r_rtr_cnt-1)])
                                        next->r_tim_lastsent[(next->r_rtr_cnt-1)] = nrsm->r_tim_lastsent[(nrsm->r_rtr_cnt-1)];
                                /*
                                 * And we must keep the newest ack arrival time.
                                 */
                                if (next->r_ack_arrival <
                                    rack_to_usec_ts(&rack->r_ctl.act_rcv_time))
                                        next->r_ack_arrival = rack_to_usec_ts(&rack->r_ctl.act_rcv_time);


                                /* We don't need to adjust rsm, it did not change */
                                /* Clear out the dup ack count of the remainder */
                                rsm->r_dupack = 0;
                                rsm->r_just_ret = 0;
                                rack_log_retran_reason(rack, rsm, __LINE__, 0, 2);
                                /* Now lets make sure our fudge block is right */
                                nrsm->r_start = start;
                                /* Check if the ack was too soon i.e. reordering + ack arrives too quickly */
                                prohibit_marking = rack_check_reorder_ack(tp, rack, nrsm, nrsm->r_end, cts, 0, __LINE__);
                                /* Now lets update all the stats and such */
                                rack_update_rtt(tp, rack, nrsm, to, cts, SACKED, 0);
                                if (rack->app_limited_needs_set)
                                        rack_need_set_test(tp, rack, nrsm, tp->snd_una, __LINE__, RACK_USE_END);
                                changed += (nrsm->r_end - nrsm->r_start);
                                rack->r_ctl.rc_sacked += (nrsm->r_end - nrsm->r_start);
                                if (rsm->r_flags & RACK_WAS_LOST) {
                                        int my_chg;

                                        /*
                                         * Note here we do not use our rack_mark_nolonger_lost() function
                                         * since we are moving our data pointer around and the
                                         * ack'ed side is already not considered lost.
                                         */
                                        my_chg = (nrsm->r_end - nrsm->r_start);
                                        KASSERT((rack->r_ctl.rc_considered_lost >= my_chg),
                                                ("rsm:%p rack:%p rc_considered_lost goes negative", rsm,  rack));
                                        if (my_chg <= rack->r_ctl.rc_considered_lost)
                                                rack->r_ctl.rc_considered_lost -= my_chg;
                                        else
                                                rack->r_ctl.rc_considered_lost = 0;
                                }
                                if (nrsm->r_flags & RACK_SACK_PASSED) {
                                        rack->r_ctl.rc_reorder_ts = cts;
                                        if (rack->r_ctl.rc_reorder_ts == 0)
                                                rack->r_ctl.rc_reorder_ts = 1;
                                }
                                /*
                                 * Now we want to go up from rsm (the
                                 * one left un-acked) to the next one
                                 * in the tmap. We do this so when
                                 * we walk backwards we include marking
                                 * sack-passed on rsm (The one passed in
                                 * is skipped since it is generally called
                                 * on something sacked before removing it
                                 * from the tmap).
                                 */
                                if (rsm->r_in_tmap) {
                                        nrsm = TAILQ_NEXT(rsm, r_tnext);
                                        /*
                                         * Now that we have the next
                                         * one walk backwards from there.
                                         */
                                        if (nrsm && nrsm->r_in_tmap && (prohibit_marking == 0))
                                                rack_log_sack_passed(tp, rack, nrsm, cts, __LINE__);
                                }
                                /* Now are we done? */
                                if (SEQ_LT(end, next->r_end) ||
                                    (end == next->r_end)) {
                                        /* Done with block */
                                        goto out;
                                }
                                rack_log_map_chg(tp, rack, &stack_map, rsm, next, MAP_SACK_M1, end, __LINE__);
                                /* Postion for the next block */
                                start = next->r_end;
                                rsm = tqhash_next(rack->r_ctl.tqh, next);
                                if (rsm == NULL)
                                        goto out;
                        } else {
                                /**
                                 * We can't use any hookery here, so we
                                 * need to split the map. We enter like
                                 * so:
                                 *  rsm      |--------|
                                 *  sackblk       |----->
                                 * We will add the new block nrsm and
                                 * that will be the new portion, and then
                                 * fall through after reseting rsm. So we
                                 * split and look like this:
                                 *  rsm      |----|
                                 *  sackblk       |----->
                                 *  nrsm          |---|
                                 * We then fall through reseting
                                 * rsm to nrsm, so the next block
                                 * picks it up.
                                 */
                                nrsm = rack_alloc_limit(rack, RACK_LIMIT_TYPE_SPLIT);
                                if (nrsm == NULL) {
                                        /*
                                         * failed XXXrrs what can we do but loose the sack
                                         * info?
                                         */
                                        goto out;
                                }
                                rack_clone_rsm(rack, nrsm, rsm, start);
                                rsm->r_just_ret = 0;
#ifndef INVARIANTS
                                (void)tqhash_insert(rack->r_ctl.tqh, nrsm);
#else
                                if ((insret = tqhash_insert(rack->r_ctl.tqh, nrsm)) != 0) {
                                        panic("Insert in tailq_hash of %p fails ret:%d rack:%p rsm:%p",
                                              nrsm, insret, rack, rsm);
                                }
#endif
                                if (rsm->r_in_tmap) {
                                        TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, rsm, nrsm, r_tnext);
                                        nrsm->r_in_tmap = 1;
                                }
                                rack_log_map_chg(tp, rack, NULL, rsm, nrsm, MAP_SACK_M2, end, __LINE__);
                                rsm->r_flags &= (~RACK_HAS_FIN);
                                /* Check if the ack was too soon i.e. reordering + ack arrives too quickly */
                                prohibit_marking = rack_check_reorder_ack(tp, rack, nrsm, nrsm->r_end, cts, 0, __LINE__);
                                /* Position us to point to the new nrsm that starts the sack blk */
                                rsm = nrsm;
                        }
                } else {
                        /* Already sacked this piece */
                        if (end == rsm->r_end) {
                                /* Done with block */
                                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
                                goto out;
                        } else if (SEQ_LT(end, rsm->r_end)) {
                                /* A partial sack to a already sacked block */
                                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
                                goto out;
                        } else {
                                /*
                                 * The end goes beyond this guy
                                 * reposition the start to the
                                 * next block.
                                 */
                                start = rsm->r_end;
                                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
                                if (rsm == NULL)
                                        goto out;
                        }
                }
        }
        if (SEQ_GEQ(end, rsm->r_end)) {
                /**
                 * The end of this block is either beyond this guy or right
                 * at this guy. I.e.:
                 *  rsm ---                 |-----|
                 *  end                     |-----|
                 *  <or>
                 *  end                     |---------|
                 */
                if ((rsm->r_flags & RACK_ACKED) == 0) {
                        /*
                         * Is it a TLP of interest?
                         */
                        if ((rsm->r_flags & RACK_TLP) &&
                            (rsm->r_rtr_cnt > 1)) {
                                /*
                                 * We are splitting a rxt TLP, check
                                 * if we need to save off the start/end
                                 */
                                if (rack->rc_last_tlp_acked_set &&
                                    (is_rsm_inside_declared_tlp_block(rack, rsm))) {
                                        /*
                                         * We already turned this on since we are inside
                                         * the previous one was a partially sack now we
                                         * are getting another one (maybe all of it).
                                         */
                                        rack_log_dsack_event(rack, 10, __LINE__, rsm->r_start, rsm->r_end);
                                        /*
                                         * Lets make sure we have all of it though.
                                         */
                                        if (SEQ_LT(rsm->r_start, rack->r_ctl.last_tlp_acked_start)) {
                                                rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                                     rack->r_ctl.last_tlp_acked_end);
                                        }
                                        if (SEQ_GT(rsm->r_end, rack->r_ctl.last_tlp_acked_end)) {
                                                rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                                     rack->r_ctl.last_tlp_acked_end);
                                        }
                                } else {
                                        rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                        rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                        rack->rc_last_tlp_past_cumack = 0;
                                        rack->rc_last_tlp_acked_set = 1;
                                        rack_log_dsack_event(rack, 8, __LINE__, rsm->r_start, rsm->r_end);
                                }
                        }
                        rack_update_rtt(tp, rack, rsm, to, cts, SACKED, 0);
                        changed += (rsm->r_end - rsm->r_start);
                        /* Check if the ack was too soon i.e. reordering + ack arrives too quickly */
                        prohibit_marking = rack_check_reorder_ack(tp, rack, rsm, rsm->r_end, cts, 0, __LINE__);
                        /* You get a count for acking a whole segment or more */
                        if (rsm->r_flags & RACK_WAS_LOST) {
                                /*
                                 * Here we can use the inline function since
                                 * the rsm is truly marked lost and now no longer lost.
                                 */
                                rack_mark_nolonger_lost(rack, rsm);
                        }
                        rack->r_ctl.rc_sacked += (rsm->r_end - rsm->r_start);
                        if (rsm->r_in_tmap && (prohibit_marking == 0)) /* should be true */
                                rack_log_sack_passed(tp, rack, rsm, cts, __LINE__);

                        /* Is Reordering occuring? */
                        if (rsm->r_flags & RACK_SACK_PASSED) {
                                rsm->r_flags &= ~RACK_SACK_PASSED;
                                rack->r_ctl.rc_reorder_ts = cts;
                                if (rack->r_ctl.rc_reorder_ts == 0)
                                        rack->r_ctl.rc_reorder_ts = 1;
                        }
                        if (rack->app_limited_needs_set)
                                rack_need_set_test(tp, rack, rsm, tp->snd_una, __LINE__, RACK_USE_END);
                        rsm->r_ack_arrival = rack_to_usec_ts(&rack->r_ctl.act_rcv_time);
                        rsm->r_flags |= RACK_ACKED;
                        rack_update_pcm_ack(rack, 0, rsm->r_start, rsm->r_end);
                        if (rsm->r_in_tmap) {
                                TAILQ_REMOVE(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                                rsm->r_in_tmap = 0;
                        }
                        rack_log_map_chg(tp, rack, NULL, rsm, NULL, MAP_SACK_M3, end, __LINE__);
                }
                if (end == rsm->r_end) {
                        /* This block only - done, setup for next */
                        goto out;
                }
                /*
                 * There is more not coverend by this rsm move on
                 * to the next block in the tail queue hash table.
                 */
                nrsm = tqhash_next(rack->r_ctl.tqh, rsm);
                start = rsm->r_end;
                rsm = nrsm;
                if (rsm == NULL)
                        goto out;
                goto do_rest_ofb;
        }
        /**
         * The end of this sack block is smaller than
         * our rsm i.e.:
         *  rsm ---                 |-----|
         *  end                     |--|
         */
        if ((rsm->r_flags & RACK_ACKED) == 0) {
                /*
                 * Is it a TLP of interest?
                 */
                if ((rsm->r_flags & RACK_TLP) &&
                    (rsm->r_rtr_cnt > 1)) {
                        /*
                         * We are splitting a rxt TLP, check
                         * if we need to save off the start/end
                         */
                        if (rack->rc_last_tlp_acked_set &&
                            (is_rsm_inside_declared_tlp_block(rack, rsm))) {
                                /*
                                 * We already turned this on since we are inside
                                 * the previous one was a partially sack now we
                                 * are getting another one (maybe all of it).
                                 */
                                rack_log_dsack_event(rack, 10, __LINE__, rsm->r_start, rsm->r_end);
                                /*
                                 * Lets make sure we have all of it though.
                                 */
                                if (SEQ_LT(rsm->r_start, rack->r_ctl.last_tlp_acked_start)) {
                                        rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                        rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                             rack->r_ctl.last_tlp_acked_end);
                                }
                                if (SEQ_GT(rsm->r_end, rack->r_ctl.last_tlp_acked_end)) {
                                        rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                        rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                             rack->r_ctl.last_tlp_acked_end);
                                }
                        } else {
                                rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                rack->rc_last_tlp_past_cumack = 0;
                                rack->rc_last_tlp_acked_set = 1;
                                rack_log_dsack_event(rack, 8, __LINE__, rsm->r_start, rsm->r_end);
                        }
                }
                /*
                 * Hookery can only be used if the two entries
                 * are in the same bucket and neither one of
                 * them staddle the bucket line.
                 */
                prev = tqhash_prev(rack->r_ctl.tqh, rsm);
                if (prev &&
                    (rsm->bindex == prev->bindex) &&
                    ((rsm->r_flags & RACK_STRADDLE) == 0) &&
                    ((prev->r_flags & RACK_STRADDLE) == 0) &&
                    ((prev->r_flags & RACK_WAS_SACKPASS) == 0) &&
                    ((rsm->r_flags & RACK_WAS_SACKPASS) == 0) &&
                    ((rsm->r_flags & RACK_IS_PCM) == 0) &&
                    ((prev->r_flags & RACK_IS_PCM) == 0) &&
                    (rsm->r_flags & RACK_IN_GP_WIN) &&
                    (prev->r_flags & RACK_IN_GP_WIN))
                        can_use_hookery = 1;
                else
                        can_use_hookery = 0;
                if (prev && can_use_hookery &&
                    (prev->r_flags & RACK_ACKED)) {
                        /**
                         * Goal, we want the right remainder of rsm to shrink
                         * in place and span from (rsm->r_start = end) to rsm->r_end.
                         * We want to expand prev to go all the way
                         * to prev->r_end <- end.
                         * so in the tree we have before:
                         *   prev     |--------|         (acked)
                         *   rsm               |-------| (non-acked)
                         *   sackblk           |-|
                         * We churn it so we end up with
                         *   prev     |----------|       (acked)
                         *   rsm                 |-----| (non-acked)
                         *   nrsm              |-| (temporary)
                         *
                         * Note if either prev/rsm is a TLP we don't
                         * do this.
                         */
                        nrsm = &stack_map;
                        memcpy(nrsm, rsm, sizeof(struct rack_sendmap));
                        tqhash_update_end(rack->r_ctl.tqh, prev, end);
                        rsm->r_start = end;
                        rsm->r_flags |= RACK_SHUFFLED;
                        prev->r_flags |= RACK_SHUFFLED;
                        /* Now adjust nrsm (stack copy) to be
                         * the one that is the small
                         * piece that was "sacked".
                         */
                        nrsm->r_end = end;
                        rsm->r_dupack = 0;
                        /* Check if the ack was too soon i.e. reordering + ack arrives too quickly */
                        prohibit_marking = rack_check_reorder_ack(tp, rack, nrsm, nrsm->r_end, cts, 0, __LINE__);
                        /*
                         * Which timestamp do we keep? It is rather
                         * important in GP measurements to have the
                         * accurate end of the send window.
                         *
                         * We keep the largest value, which is the newest
                         * send. We do this in case a segment that is
                         * joined together and not part of a GP estimate
                         * later gets expanded into the GP estimate.
                         *
                         * We prohibit the merging of unlike kinds i.e.
                         * all pieces that are in the GP estimate can be
                         * merged and all pieces that are not in a GP estimate
                         * can be merged, but not disimilar pieces. Combine
                         * this with taking the highest here and we should
                         * be ok unless of course the client reneges. Then
                         * all bets are off.
                         */
                        if(prev->r_tim_lastsent[(prev->r_rtr_cnt-1)] <
                           nrsm->r_tim_lastsent[(nrsm->r_rtr_cnt-1)]) {
                                prev->r_tim_lastsent[(prev->r_rtr_cnt-1)] = nrsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)];
                        }
                        /*
                         * And we must keep the newest ack arrival time.
                         */

                        if(prev->r_ack_arrival <
                           rack_to_usec_ts(&rack->r_ctl.act_rcv_time))
                                prev->r_ack_arrival = rack_to_usec_ts(&rack->r_ctl.act_rcv_time);

                        rack_log_retran_reason(rack, rsm, __LINE__, 0, 2);
                        /*
                         * Now that the rsm has had its start moved forward
                         * lets go ahead and get its new place in the world.
                         */
                        rack_setup_offset_for_rsm(rack, prev, rsm);
                        /*
                         * Now nrsm is our new little piece
                         * that is acked (which was merged
                         * to prev). Update the rtt and changed
                         * based on that. Also check for reordering.
                         */
                        rack_update_rtt(tp, rack, nrsm, to, cts, SACKED, 0);
                        if (rack->app_limited_needs_set)
                                rack_need_set_test(tp, rack, nrsm, tp->snd_una, __LINE__, RACK_USE_END);
                        changed += (nrsm->r_end - nrsm->r_start);
                        rack->r_ctl.rc_sacked += (nrsm->r_end - nrsm->r_start);
                        if (rsm->r_flags & RACK_WAS_LOST) {
                                int my_chg;

                                /*
                                 * Note here we are using hookery again so we can't
                                 * use our rack_mark_nolonger_lost() function.
                                 */
                                my_chg = (nrsm->r_end - nrsm->r_start);
                                KASSERT((rack->r_ctl.rc_considered_lost >= my_chg),
                                        ("rsm:%p rack:%p rc_considered_lost goes negative", rsm,  rack));
                                if (my_chg <= rack->r_ctl.rc_considered_lost)
                                        rack->r_ctl.rc_considered_lost -= my_chg;
                                else
                                        rack->r_ctl.rc_considered_lost = 0;
                        }
                        if (nrsm->r_flags & RACK_SACK_PASSED) {
                                rack->r_ctl.rc_reorder_ts = cts;
                                if (rack->r_ctl.rc_reorder_ts == 0)
                                        rack->r_ctl.rc_reorder_ts = 1;
                        }
                        rack_log_map_chg(tp, rack, prev, &stack_map, rsm, MAP_SACK_M4, end, __LINE__);
                        rsm = prev;
                } else {
                        /**
                         * This is the case where our previous
                         * block is not acked either, so we must
                         * split the block in two.
                         */
                        nrsm = rack_alloc_limit(rack, RACK_LIMIT_TYPE_SPLIT);
                        if (nrsm == NULL) {
                                /* failed rrs what can we do but loose the sack info? */
                                goto out;
                        }
                        if ((rsm->r_flags & RACK_TLP) &&
                            (rsm->r_rtr_cnt > 1)) {
                                /*
                                 * We are splitting a rxt TLP, check
                                 * if we need to save off the start/end
                                 */
                                if (rack->rc_last_tlp_acked_set &&
                                    (is_rsm_inside_declared_tlp_block(rack, rsm))) {
                                        /*
                                         * We already turned this on since this block is inside
                                         * the previous one was a partially sack now we
                                         * are getting another one (maybe all of it).
                                         */
                                        rack_log_dsack_event(rack, 10, __LINE__, rsm->r_start, rsm->r_end);
                                        /*
                                         * Lets make sure we have all of it though.
                                         */
                                        if (SEQ_LT(rsm->r_start, rack->r_ctl.last_tlp_acked_start)) {
                                                rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                                     rack->r_ctl.last_tlp_acked_end);
                                        }
                                        if (SEQ_GT(rsm->r_end, rack->r_ctl.last_tlp_acked_end)) {
                                                rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                                     rack->r_ctl.last_tlp_acked_end);
                                        }
                                } else {
                                        rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                        rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                        rack->rc_last_tlp_acked_set = 1;
                                        rack->rc_last_tlp_past_cumack = 0;
                                        rack_log_dsack_event(rack, 8, __LINE__, rsm->r_start, rsm->r_end);
                                }
                        }
                        /**
                         * In this case nrsm becomes
                         * nrsm->r_start = end;
                         * nrsm->r_end = rsm->r_end;
                         * which is un-acked.
                         * <and>
                         * rsm->r_end = nrsm->r_start;
                         * i.e. the remaining un-acked
                         * piece is left on the left
                         * hand side.
                         *
                         * So we start like this
                         * rsm      |----------| (not acked)
                         * sackblk  |---|
                         * build it so we have
                         * rsm      |---|         (acked)
                         * nrsm         |------|  (not acked)
                         */
                        rack_clone_rsm(rack, nrsm, rsm, end);
                        rsm->r_flags &= (~RACK_HAS_FIN);
                        rsm->r_just_ret = 0;
#ifndef INVARIANTS
                        (void)tqhash_insert(rack->r_ctl.tqh, nrsm);
#else
                        if ((insret = tqhash_insert(rack->r_ctl.tqh, nrsm)) != 0) {
                                panic("Insert in tailq_hash of %p fails ret:% rack:%p rsm:%p",
                                      nrsm, insret, rack, rsm);
                        }
#endif
                        if (rsm->r_in_tmap) {
                                TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, rsm, nrsm, r_tnext);
                                nrsm->r_in_tmap = 1;
                        }
                        nrsm->r_dupack = 0;
                        /* Check if the ack was too soon i.e. reordering + ack arrives too quickly */
                        prohibit_marking = rack_check_reorder_ack(tp, rack, nrsm, nrsm->r_end, cts, 0, __LINE__);
                        rack_log_retran_reason(rack, nrsm, __LINE__, 0, 2);
                        rack_update_rtt(tp, rack, rsm, to, cts, SACKED, 0);
                        changed += (rsm->r_end - rsm->r_start);
                        if (rsm->r_flags & RACK_WAS_LOST) {
                                /*
                                 * Here it is safe to use our function.
                                 */
                                rack_mark_nolonger_lost(rack, rsm);
                        }
                        rack->r_ctl.rc_sacked += (rsm->r_end - rsm->r_start);

                        if (rsm->r_in_tmap && (prohibit_marking == 0)) /* should be true */
                                rack_log_sack_passed(tp, rack, rsm, cts, __LINE__);
                        /* Is Reordering occuring? */
                        if (rsm->r_flags & RACK_SACK_PASSED) {
                                rsm->r_flags &= ~RACK_SACK_PASSED;
                                rack->r_ctl.rc_reorder_ts = cts;
                                if (rack->r_ctl.rc_reorder_ts == 0)
                                        rack->r_ctl.rc_reorder_ts = 1;
                        }
                        if (rack->app_limited_needs_set)
                                rack_need_set_test(tp, rack, rsm, tp->snd_una, __LINE__, RACK_USE_END);
                        rsm->r_ack_arrival = rack_to_usec_ts(&rack->r_ctl.act_rcv_time);
                        rsm->r_flags |= RACK_ACKED;
                        rack_update_pcm_ack(rack, 0, rsm->r_start, rsm->r_end);
                        rack_log_map_chg(tp, rack, NULL, rsm, nrsm, MAP_SACK_M5, end, __LINE__);
                        if (rsm->r_in_tmap) {
                                TAILQ_REMOVE(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                                rsm->r_in_tmap = 0;
                        }
                }
        }
out:
        if (rsm &&
            ((rsm->r_flags & RACK_TLP) == 0) &&
            (rsm->r_flags & RACK_ACKED)) {
                /*
                 * Now can we merge where we worked
                 * with either the previous or
                 * next block?
                 */
                next = tqhash_next(rack->r_ctl.tqh, rsm);
                while (next) {
                        if (next->r_flags & RACK_TLP)
                                break;
                        /* Only allow merges between ones in or out of GP window */
                        if ((next->r_flags & RACK_IN_GP_WIN) &&
                            ((rsm->r_flags & RACK_IN_GP_WIN) == 0)) {
                                break;
                        }
                        /* We can't merge retransmitted with sack-pass set */
                        if ((rsm->r_flags & RACK_WAS_SACKPASS) ||
                            (next->r_flags & RACK_WAS_SACKPASS))
                                break;
                        if ((rsm->r_flags & RACK_IN_GP_WIN) &&
                            ((next->r_flags & RACK_IN_GP_WIN) == 0)) {
                                break;
                        }
                        if (rsm->bindex != next->bindex)
                                break;
                        if (rsm->r_flags & RACK_STRADDLE)
                                break;
                        if (rsm->r_flags & RACK_IS_PCM)
                                break;
                        if (next->r_flags & RACK_STRADDLE)
                                break;
                        if (next->r_flags & RACK_IS_PCM)
                                break;
                        if (next->r_flags & RACK_ACKED) {
                                /* yep this and next can be merged */
                                rsm = rack_merge_rsm(rack, rsm, next);
                                next = tqhash_next(rack->r_ctl.tqh, rsm);
                        } else
                                break;
                }
                /* Now what about the previous? */
                prev = tqhash_prev(rack->r_ctl.tqh, rsm);
                while (prev) {
                        if (prev->r_flags & RACK_TLP)
                                break;
                        /* Only allow merges between ones in or out of GP window */
                        if ((prev->r_flags & RACK_IN_GP_WIN) &&
                            ((rsm->r_flags & RACK_IN_GP_WIN) == 0)) {
                                break;
                        }
                        /* We can't merge retransmitted with sack-pass set */
                        if ((rsm->r_flags & RACK_WAS_SACKPASS) ||
                            (prev->r_flags & RACK_WAS_SACKPASS))
                                break;
                        if ((rsm->r_flags & RACK_IN_GP_WIN) &&
                            ((prev->r_flags & RACK_IN_GP_WIN) == 0)) {
                                break;
                        }
                        if (rsm->bindex != prev->bindex)
                                break;
                        if (rsm->r_flags & RACK_STRADDLE)
                                break;
                        if (rsm->r_flags & RACK_IS_PCM)
                                break;
                        if (prev->r_flags & RACK_STRADDLE)
                                break;
                        if (prev->r_flags & RACK_IS_PCM)
                                break;
                        if (prev->r_flags & RACK_ACKED) {
                                /* yep the previous and this can be merged */
                                rsm = rack_merge_rsm(rack, prev, rsm);
                                prev = tqhash_prev(rack->r_ctl.tqh, rsm);
                        } else
                                break;
                }
        }
        if (used_ref == 0) {
                counter_u64_add(rack_sack_proc_all, 1);
        } else {
                counter_u64_add(rack_sack_proc_short, 1);
        }
        /* Save off the next one for quick reference. */
        nrsm = tqhash_find(rack->r_ctl.tqh, end);
        *prsm = rack->r_ctl.rc_sacklast = nrsm;
        return (changed);
}

static void inline
rack_peer_reneges(struct tcp_rack *rack, struct rack_sendmap *rsm, tcp_seq th_ack)
{
        struct rack_sendmap *tmap;

        tmap = NULL;
        while (rsm && (rsm->r_flags & RACK_ACKED)) {
                /* Its no longer sacked, mark it so */
                rack->r_ctl.rc_sacked -= (rsm->r_end - rsm->r_start);
#ifdef INVARIANTS
                if (rsm->r_in_tmap) {
                        panic("rack:%p rsm:%p flags:0x%x in tmap?",
                              rack, rsm, rsm->r_flags);
                }
#endif
                rsm->r_flags &= ~(RACK_ACKED|RACK_SACK_PASSED|RACK_WAS_SACKPASS);
                /* Rebuild it into our tmap */
                if (tmap == NULL) {
                        TAILQ_INSERT_HEAD(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                        tmap = rsm;
                } else {
                        TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, tmap, rsm, r_tnext);
                        tmap = rsm;
                }
                tmap->r_in_tmap = 1;
                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
        }
        /*
         * Now lets possibly clear the sack filter so we start
         * recognizing sacks that cover this area.
         */
        sack_filter_clear(&rack->r_ctl.rack_sf, th_ack);

}


static void inline
rack_rsm_sender_update(struct tcp_rack *rack, struct tcpcb *tp, struct rack_sendmap *rsm, uint8_t from)
{
        /*
         * We look at advancing the end send time for our GP
         * measurement tracking only as the cumulative acknowledgment
         * moves forward. You might wonder about this, why not
         * at every transmission or retransmission within the
         * GP window update the rc_gp_cumack_ts? Well its rather
         * nuanced but basically the GP window *may* expand (as
         * it does below) or worse and harder to track it may shrink.
         *
         * This last makes it impossible to track at the time of
         * the send, since you may set forward your rc_gp_cumack_ts
         * when you send, because that send *is* in your currently
         * "guessed" window, but then it shrinks. Now which was
         * the send time of the last bytes in the window, by the
         * time you ask that question that part of the sendmap
         * is freed. So you don't know and you will have too
         * long of send window. Instead by updating the time
         * marker only when the cumack advances this assures us
         * that we will have only the sends in the window of our
         * GP measurement.
         *
         * Another complication from this is the
         * merging of sendmap entries. During SACK processing this
         * can happen to conserve the sendmap size. That breaks
         * everything down in tracking the send window of the GP
         * estimate. So to prevent that and keep it working with
         * a tiny bit more limited merging, we only allow like
         * types to be merged. I.e. if two sends are in the GP window
         * then its ok to merge them together. If two sends are not
         * in the GP window its ok to merge them together too. Though
         * one send in and one send out cannot be merged. We combine
         * this with never allowing the shrinking of the GP window when
         * we are in recovery so that we can properly calculate the
         * sending times.
         *
         * This all of course seems complicated, because it is.. :)
         *
         * The cum-ack is being advanced upon the sendmap.
         * If we are not doing a GP estimate don't
         * proceed.
         */
        uint64_t ts;

        if ((tp->t_flags & TF_GPUTINPROG) == 0)
                return;
        /*
         * If this sendmap entry is going
         * beyond the measurement window we had picked,
         * expand the measurement window by that much.
         */
        if (SEQ_GT(rsm->r_end, tp->gput_ack)) {
                tp->gput_ack = rsm->r_end;
        }
        /*
         * If we have not setup a ack, then we
         * have no idea if the newly acked pieces
         * will be "in our seq measurement range". If
         * it is when we clear the app_limited_needs_set
         * flag the timestamp will be updated.
         */
        if (rack->app_limited_needs_set)
                return;
        /*
         * Finally, we grab out the latest timestamp
         * that this packet was sent and then see
         * if:
         *  a) The packet touches are newly defined GP range.
         *  b) The time is greater than (newer) than the
         *     one we currently have. If so we update
         *     our sending end time window.
         *
         * Note we *do not* do this at send time. The reason
         * is that if you do you *may* pick up a newer timestamp
         * for a range you are not going to measure. We project
         * out how far and then sometimes modify that to be
         * smaller. If that occurs then you will have a send
         * that does not belong to the range included.
         */
        if ((ts = rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)]) <=
            rack->r_ctl.rc_gp_cumack_ts)
                return;
        if (rack_in_gp_window(tp, rsm)) {
                rack->r_ctl.rc_gp_cumack_ts = ts;
                rack_log_gpset(rack, tp->gput_ack, (uint32_t)ts, rsm->r_end,
                               __LINE__, from, rsm);
        }
}

static void
rack_process_to_cumack(struct tcpcb *tp, struct tcp_rack *rack, register uint32_t th_ack, uint32_t cts, struct tcpopt *to, uint64_t acktime)
{
        struct rack_sendmap *rsm;
        /*
         * The ACK point is advancing to th_ack, we must drop off
         * the packets in the rack log and calculate any eligble
         * RTT's.
         */

        if (sack_filter_blks_used(&rack->r_ctl.rack_sf)) {
                /*
                 * If we have some sack blocks in the filter
                 * lets prune them out by calling sfb with no blocks.
                 */
                sack_filter_blks(tp, &rack->r_ctl.rack_sf, NULL, 0, th_ack);
        }
        if (SEQ_GT(th_ack, tp->snd_una)) {
                /* Clear any app ack remembered settings */
                rack->r_ctl.cleared_app_ack = 0;
        }
        rack->r_wanted_output = 1;
        if (SEQ_GT(th_ack, tp->snd_una))
                rack->r_ctl.last_cumack_advance = acktime;

        /* Tend any TLP that has been marked for 1/2 the seq space (its old)  */
        if ((rack->rc_last_tlp_acked_set == 1)&&
            (rack->rc_last_tlp_past_cumack == 1) &&
            (SEQ_GT(rack->r_ctl.last_tlp_acked_start, th_ack))) {
                /*
                 * We have reached the point where our last rack
                 * tlp retransmit sequence is ahead of the cum-ack.
                 * This can only happen when the cum-ack moves all
                 * the way around (its been a full 2^^31+1 bytes
                 * or more since we sent a retransmitted TLP). Lets
                 * turn off the valid flag since its not really valid.
                 *
                 * Note since sack's also turn on this event we have
                 * a complication, we have to wait to age it out until
                 * the cum-ack is by the TLP before checking which is
                 * what the next else clause does.
                 */
                rack_log_dsack_event(rack, 9, __LINE__,
                                     rack->r_ctl.last_tlp_acked_start,
                                     rack->r_ctl.last_tlp_acked_end);
                rack->rc_last_tlp_acked_set = 0;
                rack->rc_last_tlp_past_cumack = 0;
        } else if ((rack->rc_last_tlp_acked_set == 1) &&
                   (rack->rc_last_tlp_past_cumack == 0) &&
                   (SEQ_GEQ(th_ack, rack->r_ctl.last_tlp_acked_end))) {
                /*
                 * It is safe to start aging TLP's out.
                 */
                rack->rc_last_tlp_past_cumack = 1;
        }
        /* We do the same for the tlp send seq as well */
        if ((rack->rc_last_sent_tlp_seq_valid == 1) &&
            (rack->rc_last_sent_tlp_past_cumack == 1) &&
            (SEQ_GT(rack->r_ctl.last_sent_tlp_seq,  th_ack))) {
                rack_log_dsack_event(rack, 9, __LINE__,
                                     rack->r_ctl.last_sent_tlp_seq,
                                     (rack->r_ctl.last_sent_tlp_seq +
                                      rack->r_ctl.last_sent_tlp_len));
                rack->rc_last_sent_tlp_seq_valid = 0;
                rack->rc_last_sent_tlp_past_cumack = 0;
        } else if ((rack->rc_last_sent_tlp_seq_valid == 1) &&
                   (rack->rc_last_sent_tlp_past_cumack == 0) &&
                   (SEQ_GEQ(th_ack, rack->r_ctl.last_sent_tlp_seq))) {
                /*
                 * It is safe to start aging TLP's send.
                 */
                rack->rc_last_sent_tlp_past_cumack = 1;
        }
more:
        rsm = tqhash_min(rack->r_ctl.tqh);
        if (rsm == NULL) {
                if ((th_ack - 1) == tp->iss) {
                        /*
                         * For the SYN incoming case we will not
                         * have called tcp_output for the sending of
                         * the SYN, so there will be no map. All
                         * other cases should probably be a panic.
                         */
                        return;
                }
                if (tp->t_flags & TF_SENTFIN) {
                        /* if we sent a FIN we often will not have map */
                        return;
                }
#ifdef INVARIANTS
                panic("No rack map tp:%p for state:%d ack:%u rack:%p snd_una:%u snd_max:%u\n",
                      tp,
                      tp->t_state, th_ack, rack,
                      tp->snd_una, tp->snd_max);
#endif
                return;
        }
        if (SEQ_LT(th_ack, rsm->r_start)) {
                /* Huh map is missing this */
#ifdef INVARIANTS
                printf("Rack map starts at r_start:%u for th_ack:%u huh? ts:%d rs:%d\n",
                       rsm->r_start,
                       th_ack, tp->t_state, rack->r_state);
#endif
                return;
        }
        rack_update_rtt(tp, rack, rsm, to, cts, CUM_ACKED, th_ack);

        /* Now was it a retransmitted TLP? */
        if ((rsm->r_flags & RACK_TLP) &&
            (rsm->r_rtr_cnt > 1)) {
                /*
                 * Yes, this rsm was a TLP and retransmitted, remember that
                 * since if a DSACK comes back on this we don't want
                 * to think of it as a reordered segment. This may
                 * get updated again with possibly even other TLPs
                 * in flight, but thats ok. Only when we don't send
                 * a retransmitted TLP for 1/2 the sequences space
                 * will it get turned off (above).
                 */
                if (rack->rc_last_tlp_acked_set &&
                    (is_rsm_inside_declared_tlp_block(rack, rsm))) {
                        /*
                         * We already turned this on since the end matches,
                         * the previous one was a partially ack now we
                         * are getting another one (maybe all of it).
                         */
                        rack_log_dsack_event(rack, 10, __LINE__, rsm->r_start, rsm->r_end);
                        /*
                         * Lets make sure we have all of it though.
                         */
                        if (SEQ_LT(rsm->r_start, rack->r_ctl.last_tlp_acked_start)) {
                                rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                     rack->r_ctl.last_tlp_acked_end);
                        }
                        if (SEQ_GT(rsm->r_end, rack->r_ctl.last_tlp_acked_end)) {
                                rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                                rack_log_dsack_event(rack, 11, __LINE__, rack->r_ctl.last_tlp_acked_start,
                                                     rack->r_ctl.last_tlp_acked_end);
                        }
                } else {
                        rack->rc_last_tlp_past_cumack = 1;
                        rack->r_ctl.last_tlp_acked_start = rsm->r_start;
                        rack->r_ctl.last_tlp_acked_end = rsm->r_end;
                        rack->rc_last_tlp_acked_set = 1;
                        rack_log_dsack_event(rack, 8, __LINE__, rsm->r_start, rsm->r_end);
                }
        }
        /* Now do we consume the whole thing? */
        rack->r_ctl.last_tmit_time_acked = rsm->r_tim_lastsent[(rsm->r_rtr_cnt - 1)];
        if (SEQ_GEQ(th_ack, rsm->r_end)) {
                /* Its all consumed. */
                uint32_t left;
                uint8_t newly_acked;

                if (rsm->r_flags & RACK_WAS_LOST) {
                        /*
                         * This can happen when we marked it as lost
                         * and yet before retransmitting we get an ack
                         * which can happen due to reordering.
                         */
                        rack_mark_nolonger_lost(rack, rsm);
                }
                rack_log_map_chg(tp, rack, NULL, rsm, NULL, MAP_FREE, rsm->r_end, __LINE__);
                rack->r_ctl.rc_holes_rxt -= rsm->r_rtr_bytes;
                rsm->r_rtr_bytes = 0;
                /*
                 * Record the time of highest cumack sent if its in our measurement
                 * window and possibly bump out the end.
                 */
                rack_rsm_sender_update(rack, tp, rsm, 4);
                tqhash_remove(rack->r_ctl.tqh, rsm, REMOVE_TYPE_CUMACK);
                if (rsm->r_in_tmap) {
                        TAILQ_REMOVE(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                        rsm->r_in_tmap = 0;
                }
                newly_acked = 1;
                if (rsm->r_flags & RACK_ACKED) {
                        /*
                         * It was acked on the scoreboard -- remove
                         * it from total
                         */
                        rack->r_ctl.rc_sacked -= (rsm->r_end - rsm->r_start);
                        newly_acked = 0;
                } else if (rsm->r_flags & RACK_SACK_PASSED) {
                        /*
                         * There are segments ACKED on the
                         * scoreboard further up. We are seeing
                         * reordering.
                         */
                        rsm->r_flags &= ~RACK_SACK_PASSED;
                        rsm->r_ack_arrival = rack_to_usec_ts(&rack->r_ctl.act_rcv_time);
                        rsm->r_flags |= RACK_ACKED;
                        rack->r_ctl.rc_reorder_ts = cts;
                        if (rack->r_ctl.rc_reorder_ts == 0)
                                rack->r_ctl.rc_reorder_ts = 1;
                        if (rack->r_ent_rec_ns) {
                                /*
                                 * We have sent no more, and we saw an sack
                                 * then ack arrive.
                                 */
                                rack->r_might_revert = 1;
                        }
                        rack_update_pcm_ack(rack, 1, rsm->r_start, rsm->r_end);
                } else {
                        (void)rack_check_reorder_ack(tp, rack, rsm, rsm->r_end, cts, 1, __LINE__);
                        rack_update_pcm_ack(rack, 1, rsm->r_start, rsm->r_end);
                }
                if ((rsm->r_flags & RACK_TO_REXT) &&
                    (tp->t_flags & TF_RCVD_TSTMP) &&
                    (to->to_flags & TOF_TS) &&
                    (to->to_tsecr != 0) &&
                    (tp->t_flags & TF_PREVVALID)) {
                        /*
                         * We can use the timestamp to see
                         * if this retransmission was from the
                         * first transmit. If so we made a mistake.
                         */
                        tp->t_flags &= ~TF_PREVVALID;
                        if (to->to_tsecr == rack_ts_to_msec(rsm->r_tim_lastsent[0])) {
                                /* The first transmit is what this ack is for */
                                rack_cong_signal(tp, CC_RTO_ERR, th_ack, __LINE__);
                        }
                }
                left = th_ack - rsm->r_end;
                if (rack->app_limited_needs_set && newly_acked)
                        rack_need_set_test(tp, rack, rsm, th_ack, __LINE__, RACK_USE_END_OR_THACK);
                /* Free back to zone */
                rack_free(rack, rsm);
                if (left) {
                        goto more;
                }
                /* Check for reneging */
                rsm = tqhash_min(rack->r_ctl.tqh);
                if (rsm && (rsm->r_flags & RACK_ACKED) && (th_ack == rsm->r_start)) {
                        /*
                         * The peer has moved snd_una up to
                         * the edge of this send, i.e. one
                         * that it had previously acked. The only
                         * way that can be true if the peer threw
                         * away data (space issues) that it had
                         * previously sacked (else it would have
                         * given us snd_una up to (rsm->r_end).
                         * We need to undo the acked markings here.
                         *
                         * Note we have to look to make sure th_ack is
                         * our rsm->r_start in case we get an old ack
                         * where th_ack is behind snd_una.
                         */
                        rack_peer_reneges(rack, rsm, th_ack);
                }
                return;
        }
        if (rsm->r_flags & RACK_ACKED) {
                /*
                 * It was acked on the scoreboard -- remove it from
                 * total for the part being cum-acked.
                 */
                rack->r_ctl.rc_sacked -= (th_ack - rsm->r_start);
        } else {
                rack_update_pcm_ack(rack, 1, rsm->r_start, th_ack);
        }
        /* And what about the lost flag? */
        if (rsm->r_flags & RACK_WAS_LOST) {
                /*
                 * This can happen when we marked it as lost
                 * and yet before retransmitting we get an ack
                 * which can happen due to reordering. In this
                 * case its only a partial ack of the send.
                 */
                rack_mark_nolonger_lost(rack, rsm);
        }
        /*
         * Clear the dup ack count for
         * the piece that remains.
         */
        rsm->r_dupack = 0;
        rack_log_retran_reason(rack, rsm, __LINE__, 0, 2);
        if (rsm->r_rtr_bytes) {
                /*
                 * It was retransmitted adjust the
                 * sack holes for what was acked.
                 */
                int ack_am;

                ack_am = (th_ack - rsm->r_start);
                if (ack_am >= rsm->r_rtr_bytes) {
                        rack->r_ctl.rc_holes_rxt -= ack_am;
                        rsm->r_rtr_bytes -= ack_am;
                }
        }
        /*
         * Update where the piece starts and record
         * the time of send of highest cumack sent if
         * its in our GP range.
         */
        rack_log_map_chg(tp, rack, NULL, rsm, NULL, MAP_TRIM_HEAD, th_ack, __LINE__);
        /* Now we need to move our offset forward too */
        if (rsm->m &&
            ((rsm->orig_m_len != rsm->m->m_len) ||
             (M_TRAILINGROOM(rsm->m) != rsm->orig_t_space))) {
                /* Fix up the orig_m_len and possibly the mbuf offset */
                rack_adjust_orig_mlen(rsm);
        }
        rsm->soff += (th_ack - rsm->r_start);
        rack_rsm_sender_update(rack, tp, rsm, 5);

        /*
         * Handle the special case where we retransmitted part of a segment we
         * in this case pass in th_ack which is shorter than r_end.
         */
        if (rsm->r_flags & RACK_WAS_SACKPASS) {
                rack_check_reorder_ack(tp, rack, rsm, th_ack, cts, 1, __LINE__);
        }
        /* The trim will move th_ack into r_start for us */
        tqhash_trim(rack->r_ctl.tqh, th_ack);
        /* Now do we need to move the mbuf fwd too? */
        {
                struct mbuf *m;
                uint32_t soff;

                m = rsm->m;
                soff = rsm->soff;
                if (m) {
                        while (soff >= m->m_len) {
                                soff -= m->m_len;
                                KASSERT((m->m_next != NULL),
                                        (" rsm:%p  off:%u soff:%u m:%p",
                                         rsm, rsm->soff, soff, m));
                                m = m->m_next;
                                if (m == NULL) {
                                        /*
                                         * This is a fall-back that prevents a panic. In reality
                                         * we should be able to walk the mbuf's and find our place.
                                         * At this point snd_una has not been updated with the sbcut() yet
                                         * but tqhash_trim did update rsm->r_start so the offset calcuation
                                         * should work fine. This is undesirable since we will take cache
                                         * hits to access the socket buffer. And even more puzzling is that
                                         * it happens occasionally. It should not :(
                                         */
                                        m = sbsndmbuf(&rack->rc_inp->inp_socket->so_snd,
                                                      (rsm->r_start - tp->snd_una),
                                                      &soff);
                                        break;
                                }
                        }
                        /*
                         * Now save in our updated values.
                         */
                        rsm->m = m;
                        rsm->soff = soff;
                        rsm->orig_m_len = rsm->m->m_len;
                        rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                }
        }
        if (rack->app_limited_needs_set &&
            SEQ_GEQ(th_ack, tp->gput_seq))
                rack_need_set_test(tp, rack, rsm, tp->snd_una, __LINE__, RACK_USE_BEG);
}

static void
rack_handle_might_revert(struct tcpcb *tp, struct tcp_rack *rack)
{
        struct rack_sendmap *rsm;
        int sack_pass_fnd = 0;

        if (rack->r_might_revert) {
                /*
                 * Ok we have reordering, have not sent anything, we
                 * might want to revert the congestion state if nothing
                 * further has SACK_PASSED on it. Lets check.
                 *
                 * We also get here when we have DSACKs come in for
                 * all the data that we FR'd. Note that a rxt or tlp
                 * timer clears this from happening.
                 */

                TAILQ_FOREACH(rsm, &rack->r_ctl.rc_tmap, r_tnext) {
                        if (rsm->r_flags & RACK_SACK_PASSED) {
                                sack_pass_fnd = 1;
                                break;
                        }
                }
                if (sack_pass_fnd == 0) {
                        /*
                         * We went into recovery
                         * incorrectly due to reordering!
                         */
                        int orig_cwnd;

                        rack->r_ent_rec_ns = 0;
                        orig_cwnd = tp->snd_cwnd;
                        tp->snd_ssthresh = rack->r_ctl.rc_ssthresh_at_erec;
                        tp->snd_recover = tp->snd_una;
                        rack_log_to_prr(rack, 14, orig_cwnd, __LINE__);
                        if (IN_RECOVERY(tp->t_flags)) {
                                rack_exit_recovery(tp, rack, 3);
                                if ((rack->rto_from_rec == 1) && (rack_ssthresh_rest_rto_rec != 0) ){
                                        /*
                                         * We were in recovery, had an RTO
                                         * and then re-entered recovery (more sack's arrived)
                                         * and we have properly recorded the old ssthresh from
                                         * the first recovery. We want to be able to slow-start
                                         * back to this level. The ssthresh from the timeout
                                         * and then back into recovery will end up most likely
                                         * to be min(cwnd=1mss, 2mss). Which makes it basically
                                         * so we get no slow-start after our RTO.
                                         */
                                        rack->rto_from_rec = 0;
                                        if (rack->r_ctl.rto_ssthresh > tp->snd_ssthresh)
                                                tp->snd_ssthresh = rack->r_ctl.rto_ssthresh;
                                }
                        }
                }
                rack->r_might_revert = 0;
        }
}


static int
rack_note_dsack(struct tcp_rack *rack, tcp_seq start, tcp_seq end)
{

        uint32_t am, l_end;
        int was_tlp = 0;

        if (SEQ_GT(end, start))
                am = end - start;
        else
                am = 0;
        if ((rack->rc_last_tlp_acked_set ) &&
            (SEQ_GEQ(start, rack->r_ctl.last_tlp_acked_start)) &&
            (SEQ_LEQ(end, rack->r_ctl.last_tlp_acked_end))) {
                /*
                 * The DSACK is because of a TLP which we don't
                 * do anything with the reordering window over since
                 * it was not reordering that caused the DSACK but
                 * our previous retransmit TLP.
                 */
                rack_log_dsack_event(rack, 7, __LINE__, start, end);
                was_tlp = 1;
                goto skip_dsack_round;
        }
        if (rack->rc_last_sent_tlp_seq_valid) {
                l_end = rack->r_ctl.last_sent_tlp_seq + rack->r_ctl.last_sent_tlp_len;
                if (SEQ_GEQ(start, rack->r_ctl.last_sent_tlp_seq) &&
                    (SEQ_LEQ(end, l_end))) {
                        /*
                         * This dsack is from the last sent TLP, ignore it
                         * for reordering purposes.
                         */
                        rack_log_dsack_event(rack, 7, __LINE__, start, end);
                        was_tlp = 1;
                        goto skip_dsack_round;
                }
        }
        if (rack->rc_dsack_round_seen == 0) {
                rack->rc_dsack_round_seen = 1;
                rack->r_ctl.dsack_round_end = rack->rc_tp->snd_max;
                rack->r_ctl.num_dsack++;
                rack->r_ctl.dsack_persist = 16; /* 16 is from the standard */
                rack_log_dsack_event(rack, 2, __LINE__, 0, 0);
        }
skip_dsack_round:
        /*
         * We keep track of how many DSACK blocks we get
         * after a recovery incident.
         */
        rack->r_ctl.dsack_byte_cnt += am;
        if (!IN_FASTRECOVERY(rack->rc_tp->t_flags) &&
            rack->r_ctl.retran_during_recovery &&
            (rack->r_ctl.dsack_byte_cnt >= rack->r_ctl.retran_during_recovery)) {
                /*
                 * False recovery most likely culprit is reordering. If
                 * nothing else is missing we need to revert.
                 */
                rack->r_might_revert = 1;
                rack_handle_might_revert(rack->rc_tp, rack);
                rack->r_might_revert = 0;
                rack->r_ctl.retran_during_recovery = 0;
                rack->r_ctl.dsack_byte_cnt = 0;
        }
        return (was_tlp);
}

static uint32_t
do_rack_compute_pipe(struct tcpcb *tp, struct tcp_rack *rack, uint32_t snd_una)
{
        return (((tp->snd_max - snd_una) -
                 (rack->r_ctl.rc_sacked + rack->r_ctl.rc_considered_lost)) + rack->r_ctl.rc_holes_rxt);
}

static int32_t
rack_compute_pipe(struct tcpcb *tp)
{
        return ((int32_t)do_rack_compute_pipe(tp,
                                              (struct tcp_rack *)tp->t_fb_ptr,
                                              tp->snd_una));
}

static void
rack_update_prr(struct tcpcb *tp, struct tcp_rack *rack, uint32_t changed, tcp_seq th_ack)
{
        /* Deal with changed and PRR here (in recovery only) */
        uint32_t pipe, snd_una;

        rack->r_ctl.rc_prr_delivered += changed;

        if (sbavail(&rack->rc_inp->inp_socket->so_snd) <= (tp->snd_max - tp->snd_una)) {
                /*
                 * It is all outstanding, we are application limited
                 * and thus we don't need more room to send anything.
                 * Note we use tp->snd_una here and not th_ack because
                 * the data as yet not been cut from the sb.
                 */
                rack->r_ctl.rc_prr_sndcnt = 0;
                return;
        }
        /* Compute prr_sndcnt */
        if (SEQ_GT(tp->snd_una, th_ack)) {
                snd_una = tp->snd_una;
        } else {
                snd_una = th_ack;
        }
        pipe = do_rack_compute_pipe(tp, rack, snd_una);
        if (pipe > tp->snd_ssthresh) {
                long sndcnt;

                sndcnt = rack->r_ctl.rc_prr_delivered * tp->snd_ssthresh;
                if (rack->r_ctl.rc_prr_recovery_fs > 0)
                        sndcnt /= (long)rack->r_ctl.rc_prr_recovery_fs;
                else {
                        rack->r_ctl.rc_prr_sndcnt = 0;
                        rack_log_to_prr(rack, 9, 0, __LINE__);
                        sndcnt = 0;
                }
                sndcnt++;
                if (sndcnt > (long)rack->r_ctl.rc_prr_out)
                        sndcnt -= rack->r_ctl.rc_prr_out;
                else
                        sndcnt = 0;
                rack->r_ctl.rc_prr_sndcnt = sndcnt;
                rack_log_to_prr(rack, 10, 0, __LINE__);
        } else {
                uint32_t limit;

                if (rack->r_ctl.rc_prr_delivered > rack->r_ctl.rc_prr_out)
                        limit = (rack->r_ctl.rc_prr_delivered - rack->r_ctl.rc_prr_out);
                else
                        limit = 0;
                if (changed > limit)
                        limit = changed;
                limit += ctf_fixed_maxseg(tp);
                if (tp->snd_ssthresh > pipe) {
                        rack->r_ctl.rc_prr_sndcnt = min((tp->snd_ssthresh - pipe), limit);
                        rack_log_to_prr(rack, 11, 0, __LINE__);
                } else {
                        rack->r_ctl.rc_prr_sndcnt = min(0, limit);
                        rack_log_to_prr(rack, 12, 0, __LINE__);
                }
        }
}

static void
rack_log_ack(struct tcpcb *tp, struct tcpopt *to, struct tcphdr *th, int entered_recovery, int dup_ack_struck,
             int *dsack_seen, int *sacks_seen)
{
        uint32_t changed;
        struct tcp_rack *rack;
        struct rack_sendmap *rsm;
        struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1];
        register uint32_t th_ack;
        int32_t i, j, k, num_sack_blks = 0;
        uint32_t cts, acked, ack_point;
        int loop_start = 0;
        uint32_t tsused;
        uint32_t segsiz;


        INP_WLOCK_ASSERT(tptoinpcb(tp));
        if (tcp_get_flags(th) & TH_RST) {
                /* We don't log resets */
                return;
        }
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        cts = tcp_get_usecs(NULL);
        rsm = tqhash_min(rack->r_ctl.tqh);
        changed = 0;
        th_ack = th->th_ack;
        segsiz = ctf_fixed_maxseg(rack->rc_tp);
        if (SEQ_GT(th_ack, tp->snd_una)) {
                rack_log_progress_event(rack, tp, ticks, PROGRESS_UPDATE, __LINE__);
                tp->t_acktime = ticks;
        }
        if (rsm && SEQ_GT(th_ack, rsm->r_start))
                changed = th_ack - rsm->r_start;
        if (changed) {
                rack_process_to_cumack(tp, rack, th_ack, cts, to,
                                       tcp_tv_to_lusec(&rack->r_ctl.act_rcv_time));
        }
        if ((to->to_flags & TOF_SACK) == 0) {
                /* We are done nothing left and no sack. */
                rack_handle_might_revert(tp, rack);
                /*
                 * For cases where we struck a dup-ack
                 * with no SACK, add to the changes so
                 * PRR will work right.
                 */
                if (dup_ack_struck && (changed == 0)) {
                        changed += ctf_fixed_maxseg(rack->rc_tp);
                }
                goto out;
        }
        /* Sack block processing */
        if (SEQ_GT(th_ack, tp->snd_una))
                ack_point = th_ack;
        else
                ack_point = tp->snd_una;
        for (i = 0; i < to->to_nsacks; i++) {
                bcopy((to->to_sacks + i * TCPOLEN_SACK),
                      &sack, sizeof(sack));
                sack.start = ntohl(sack.start);
                sack.end = ntohl(sack.end);
                if (SEQ_GT(sack.end, sack.start) &&
                    SEQ_GT(sack.start, ack_point) &&
                    SEQ_LT(sack.start, tp->snd_max) &&
                    SEQ_GT(sack.end, ack_point) &&
                    SEQ_LEQ(sack.end, tp->snd_max)) {
                        sack_blocks[num_sack_blks] = sack;
                        num_sack_blks++;
                } else if (SEQ_LEQ(sack.start, th_ack) &&
                           SEQ_LEQ(sack.end, th_ack)) {
                        int was_tlp;

                        if (dsack_seen != NULL)
                                *dsack_seen = 1;
                        was_tlp = rack_note_dsack(rack, sack.start, sack.end);
                        /*
                         * Its a D-SACK block.
                         */
                        tcp_record_dsack(tp, sack.start, sack.end, was_tlp);
                }
        }
        if (rack->rc_dsack_round_seen) {
                /* Is the dsack roound over? */
                if (SEQ_GEQ(th_ack, rack->r_ctl.dsack_round_end)) {
                        /* Yes it is */
                        rack->rc_dsack_round_seen = 0;
                        rack_log_dsack_event(rack, 3, __LINE__, 0, 0);
                }
        }
        /*
         * Sort the SACK blocks so we can update the rack scoreboard with
         * just one pass.
         */
        num_sack_blks = sack_filter_blks(tp, &rack->r_ctl.rack_sf, sack_blocks,
                                         num_sack_blks, th->th_ack);
        ctf_log_sack_filter(rack->rc_tp, num_sack_blks, sack_blocks);
        if (sacks_seen != NULL)
                *sacks_seen = num_sack_blks;
        if (num_sack_blks == 0) {
                /* Nothing to sack */
                goto out;
        }
        /* Its a sack of some sort */
        if (num_sack_blks < 2) {
                /* Only one, we don't need to sort */
                goto do_sack_work;
        }
        /* Sort the sacks */
        for (i = 0; i < num_sack_blks; i++) {
                for (j = i + 1; j < num_sack_blks; j++) {
                        if (SEQ_GT(sack_blocks[i].end, sack_blocks[j].end)) {
                                sack = sack_blocks[i];
                                sack_blocks[i] = sack_blocks[j];
                                sack_blocks[j] = sack;
                        }
                }
        }
        /*
         * Now are any of the sack block ends the same (yes some
         * implementations send these)?
         */
again:
        if (num_sack_blks == 0)
                goto out;
        if (num_sack_blks > 1) {
                for (i = 0; i < num_sack_blks; i++) {
                        for (j = i + 1; j < num_sack_blks; j++) {
                                if (sack_blocks[i].end == sack_blocks[j].end) {
                                        /*
                                         * Ok these two have the same end we
                                         * want the smallest end and then
                                         * throw away the larger and start
                                         * again.
                                         */
                                        if (SEQ_LT(sack_blocks[j].start, sack_blocks[i].start)) {
                                                /*
                                                 * The second block covers
                                                 * more area use that
                                                 */
                                                sack_blocks[i].start = sack_blocks[j].start;
                                        }
                                        /*
                                         * Now collapse out the dup-sack and
                                         * lower the count
                                         */
                                        for (k = (j + 1); k < num_sack_blks; k++) {
                                                sack_blocks[j].start = sack_blocks[k].start;
                                                sack_blocks[j].end = sack_blocks[k].end;
                                                j++;
                                        }
                                        num_sack_blks--;
                                        goto again;
                                }
                        }
                }
        }
do_sack_work:
        /*
         * First lets look to see if
         * we have retransmitted and
         * can use the transmit next?
         */
        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
        if (rsm &&
            SEQ_GT(sack_blocks[0].end, rsm->r_start) &&
            SEQ_LT(sack_blocks[0].start, rsm->r_end)) {
                /*
                 * We probably did the FR and the next
                 * SACK in continues as we would expect.
                 */
                acked = rack_proc_sack_blk(tp, rack, &sack_blocks[0], to, &rsm, cts, segsiz);
                if (acked) {
                        rack->r_wanted_output = 1;
                        changed += acked;
                }
                if (num_sack_blks == 1) {
                        goto out;
                } else {
                        /*
                         * Start the loop through the
                         * rest of blocks, past the first block.
                         */
                        loop_start = 1;
                }
        }
        rsm = rack->r_ctl.rc_sacklast;
        for (i = loop_start; i < num_sack_blks; i++) {
                acked = rack_proc_sack_blk(tp, rack, &sack_blocks[i], to, &rsm, cts,  segsiz);
                if (acked) {
                        rack->r_wanted_output = 1;
                        changed += acked;
                }
        }
out:
        if (changed) {
                /* Something changed cancel the rack timer */
                rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
        }
        tsused = tcp_get_usecs(NULL);
        rsm = tcp_rack_output(tp, rack, tsused);
        if ((!IN_FASTRECOVERY(tp->t_flags)) &&
            rsm &&
            ((rsm->r_flags & RACK_MUST_RXT) == 0)) {
                /* Enter recovery */
                entered_recovery = 1;
                rack_cong_signal(tp, CC_NDUPACK, th_ack, __LINE__);
                /*
                 * When we enter recovery we need to assure we send
                 * one packet.
                 */
                if (rack->rack_no_prr == 0) {
                        rack->r_ctl.rc_prr_sndcnt = ctf_fixed_maxseg(tp);
                        rack_log_to_prr(rack, 8, 0, __LINE__);
                }
                rack->r_timer_override = 1;
                rack->r_early = 0;
                rack->r_ctl.rc_agg_early = 0;
        } else if (IN_FASTRECOVERY(tp->t_flags) &&
                   rsm &&
                   (rack->r_rr_config == 3)) {
                /*
                 * Assure we can output and we get no
                 * remembered pace time except the retransmit.
                 */
                rack->r_timer_override = 1;
                rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
                rack->r_ctl.rc_resend = rsm;
        }
        if (IN_FASTRECOVERY(tp->t_flags) &&
            (rack->rack_no_prr == 0) &&
            (entered_recovery == 0)) {
                rack_update_prr(tp, rack, changed, th_ack);
                if ((rsm && (rack->r_ctl.rc_prr_sndcnt >= ctf_fixed_maxseg(tp)) &&
                     ((tcp_in_hpts(rack->rc_tp) == 0) &&
                      ((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) == 0)))) {
                        /*
                         * If you are pacing output you don't want
                         * to override.
                         */
                        rack->r_early = 0;
                        rack->r_ctl.rc_agg_early = 0;
                        rack->r_timer_override = 1;
                }
        }
}

static void
rack_strike_dupack(struct tcp_rack *rack, tcp_seq th_ack)
{
        struct rack_sendmap *rsm;

        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
        while (rsm) {
                /*
                 * We need to skip anything already set
                 * to be retransmitted.
                 */
                if ((rsm->r_dupack >= DUP_ACK_THRESHOLD) ||
                    (rsm->r_flags & RACK_MUST_RXT)) {
                        rsm = TAILQ_NEXT(rsm, r_tnext);
                        continue;
                }
                break;
        }
        if (rsm && (rsm->r_dupack < 0xff)) {
                rsm->r_dupack++;
                if (rsm->r_dupack >= DUP_ACK_THRESHOLD) {
                        struct timeval tv;
                        uint32_t cts;
                        /*
                         * Here we see if we need to retransmit. For
                         * a SACK type connection if enough time has passed
                         * we will get a return of the rsm. For a non-sack
                         * connection we will get the rsm returned if the
                         * dupack value is 3 or more.
                         */
                        cts = tcp_get_usecs(&tv);
                        rack->r_ctl.rc_resend = tcp_rack_output(rack->rc_tp, rack, cts);
                        if (rack->r_ctl.rc_resend != NULL) {
                                if (!IN_FASTRECOVERY(rack->rc_tp->t_flags)) {
                                        rack_cong_signal(rack->rc_tp, CC_NDUPACK,
                                                         th_ack,  __LINE__);
                                }
                                rack->r_wanted_output = 1;
                                rack->r_timer_override = 1;
                                rack_log_retran_reason(rack, rsm, __LINE__, 1, 3);
                        }
                } else {
                        rack_log_retran_reason(rack, rsm, __LINE__, 0, 3);
                }
        }
}

static void
rack_check_bottom_drag(struct tcpcb *tp,
                       struct tcp_rack *rack,
                       struct socket *so)
{
        /*
         * So what is dragging bottom?
         *
         * Dragging bottom means you were under pacing and had a
         * delay in processing inbound acks waiting on our pacing
         * timer to expire. While you were waiting all of the acknowledgments
         * for the packets you sent have arrived. This means we are pacing
         * way underneath the bottleneck to the point where our Goodput
         * measurements stop working, since they require more than one
         * ack (usually at least 8 packets worth with multiple acks so we can
         * gauge the inter-ack times). If that occurs we have a real problem
         * since we are stuck in a hole that we can't get out of without
         * something speeding us up.
         *
         * We also check to see if we are widdling down to just one segment
         * outstanding. If this occurs and we have room to send in our cwnd/rwnd
         * then we are adding the delayed ack interval into our measurments and
         * we need to speed up slightly.
         */
        uint32_t segsiz, minseg;

        segsiz = ctf_fixed_maxseg(tp);
        minseg = segsiz;
        if (tp->snd_max == tp->snd_una) {
                /*
                 * We are doing dynamic pacing and we are way
                 * under. Basically everything got acked while
                 * we were still waiting on the pacer to expire.
                 *
                 * This means we need to boost the b/w in
                 * addition to any earlier boosting of
                 * the multiplier.
                 */
                uint64_t lt_bw;

                tcp_trace_point(rack->rc_tp, TCP_TP_PACED_BOTTOM);
                lt_bw = rack_get_lt_bw(rack);
                rack->rc_dragged_bottom = 1;
                rack_validate_multipliers_at_or_above100(rack);
                if ((rack->r_ctl.rack_rs.rs_flags & RACK_RTT_VALID) &&
                    (rack->dis_lt_bw == 0) &&
                    (rack->use_lesser_lt_bw == 0) &&
                    (lt_bw > 0)) {
                        /*
                         * Lets use the long-term b/w we have
                         * been getting as a base.
                         */
                        if (rack->rc_gp_filled == 0) {
                                if (lt_bw > ONE_POINT_TWO_MEG) {
                                        /*
                                         * If we have no measurement
                                         * don't let us set in more than
                                         * 1.2Mbps. If we are still too
                                         * low after pacing with this we
                                         * will hopefully have a max b/w
                                         * available to sanity check things.
                                         */
                                        lt_bw = ONE_POINT_TWO_MEG;
                                }
                                rack->r_ctl.rc_rtt_diff = 0;
                                rack->r_ctl.gp_bw = lt_bw;
                                rack->rc_gp_filled = 1;
                                if (rack->r_ctl.num_measurements < RACK_REQ_AVG)
                                        rack->r_ctl.num_measurements = RACK_REQ_AVG;
                                rack_set_pace_segments(rack->rc_tp, rack, __LINE__, NULL);
                        } else if (lt_bw > rack->r_ctl.gp_bw) {
                                rack->r_ctl.rc_rtt_diff = 0;
                                if (rack->r_ctl.num_measurements < RACK_REQ_AVG)
                                        rack->r_ctl.num_measurements = RACK_REQ_AVG;
                                rack->r_ctl.gp_bw = lt_bw;
                                rack_set_pace_segments(rack->rc_tp, rack, __LINE__, NULL);
                        } else
                                rack_increase_bw_mul(rack, -1, 0, 0, 1);
                        if ((rack->gp_ready == 0) &&
                            (rack->r_ctl.num_measurements >= rack->r_ctl.req_measurements)) {
                                /* We have enough measurements now */
                                rack->gp_ready = 1;
                                if (rack->dgp_on ||
                                    rack->rack_hibeta)
                                        rack_set_cc_pacing(rack);
                                if (rack->defer_options)
                                        rack_apply_deferred_options(rack);
                        }
                } else {
                        /*
                         * zero rtt possibly?, settle for just an old increase.
                         */
                        rack_increase_bw_mul(rack, -1, 0, 0, 1);
                }
        } else if ((IN_FASTRECOVERY(tp->t_flags) == 0) &&
                   (sbavail(&so->so_snd) > max((segsiz * (4 + rack_req_segs)),
                                               minseg)) &&
                   (rack->r_ctl.cwnd_to_use > max((segsiz * (rack_req_segs + 2)), minseg)) &&
                   (tp->snd_wnd > max((segsiz * (rack_req_segs + 2)), minseg)) &&
                   (ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked) <=
                    (segsiz * rack_req_segs))) {
                /*
                 * We are doing dynamic GP pacing and
                 * we have everything except 1MSS or less
                 * bytes left out. We are still pacing away.
                 * And there is data that could be sent, This
                 * means we are inserting delayed ack time in
                 * our measurements because we are pacing too slow.
                 */
                rack_validate_multipliers_at_or_above100(rack);
                rack->rc_dragged_bottom = 1;
                rack_increase_bw_mul(rack, -1, 0, 0, 1);
        }
}

#ifdef TCP_REQUEST_TRK
static void
rack_log_hybrid(struct tcp_rack *rack, uint32_t seq,
                struct tcp_sendfile_track *cur, uint8_t mod, int line, int err)
{
        int do_log;

        do_log = tcp_bblogging_on(rack->rc_tp);
        if (do_log == 0) {
                if ((do_log = tcp_bblogging_point_on(rack->rc_tp, TCP_BBPOINT_REQ_LEVEL_LOGGING) )== 0)
                        return;
                /* We only allow the three below with point logging on */
                if ((mod != HYBRID_LOG_RULES_APP) &&
                    (mod != HYBRID_LOG_RULES_SET) &&
                    (mod != HYBRID_LOG_REQ_COMP))
                        return;

        }
        if (do_log) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                /* Convert our ms to a microsecond */
                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex1 = seq;
                log.u_bbr.cwnd_gain = line;
                if (cur != NULL) {
                        uint64_t off;

                        log.u_bbr.flex2 = cur->start_seq;
                        log.u_bbr.flex3 = cur->end_seq;
                        log.u_bbr.flex4 = (uint32_t)((cur->localtime >> 32) & 0x00000000ffffffff);
                        log.u_bbr.flex5 = (uint32_t)(cur->localtime & 0x00000000ffffffff);
                        log.u_bbr.flex6 = cur->flags;
                        log.u_bbr.pkts_out = cur->hybrid_flags;
                        log.u_bbr.rttProp = cur->timestamp;
                        log.u_bbr.cur_del_rate = cur->cspr;
                        log.u_bbr.bw_inuse = cur->start;
                        log.u_bbr.applimited = (uint32_t)(cur->end & 0x00000000ffffffff);
                        log.u_bbr.delivered = (uint32_t)((cur->end >> 32) & 0x00000000ffffffff) ;
                        log.u_bbr.epoch = (uint32_t)(cur->deadline & 0x00000000ffffffff);
                        log.u_bbr.lt_epoch = (uint32_t)((cur->deadline >> 32) & 0x00000000ffffffff) ;
                        log.u_bbr.inhpts = 1;
#ifdef TCP_REQUEST_TRK
                        off = (uint64_t)(cur) - (uint64_t)(&rack->rc_tp->t_tcpreq_info[0]);
                        log.u_bbr.use_lt_bw = (uint8_t)(off / sizeof(struct tcp_sendfile_track));
#endif
                } else {
                        log.u_bbr.flex2 = err;
                }
                /*
                 * Fill in flex7 to be CHD (catchup|hybrid|DGP)
                 */
                log.u_bbr.flex7 = rack->rc_catch_up;
                log.u_bbr.flex7 <<= 1;
                log.u_bbr.flex7 |= rack->rc_hybrid_mode;
                log.u_bbr.flex7 <<= 1;
                log.u_bbr.flex7 |= rack->dgp_on;
                /*
                 * Compose bbr_state to be a bit wise 0000ADHF
                 * where A is the always_pace flag
                 * where D is the dgp_on flag
                 * where H is the hybrid_mode on flag
                 * where F is the use_fixed_rate flag.
                 */
                log.u_bbr.bbr_state = rack->rc_always_pace;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->dgp_on;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->rc_hybrid_mode;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->use_fixed_rate;
                log.u_bbr.flex8 = mod;
                log.u_bbr.delRate = rack->r_ctl.bw_rate_cap;
                log.u_bbr.bbr_substate = rack->r_ctl.client_suggested_maxseg;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkt_epoch = rack->rc_tp->tcp_hybrid_start;
                log.u_bbr.lost = rack->rc_tp->tcp_hybrid_error;
                log.u_bbr.pacing_gain = (uint16_t)rack->rc_tp->tcp_hybrid_stop;
                tcp_log_event(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_HYBRID_PACING_LOG, 0,
                    0, &log, false, NULL, __func__, __LINE__, &tv);
        }
}
#endif

#ifdef TCP_REQUEST_TRK
static void
rack_set_dgp_hybrid_mode(struct tcp_rack *rack, tcp_seq seq, uint32_t len, uint64_t cts)
{
        struct tcp_sendfile_track *rc_cur, *orig_ent;
        struct tcpcb *tp;
        int err = 0;

        orig_ent = rack->r_ctl.rc_last_sft;
        rc_cur = tcp_req_find_req_for_seq(rack->rc_tp, seq);
        if (rc_cur == NULL) {
                /* If not in the beginning what about the end piece */
                if (rack->rc_hybrid_mode)
                        rack_log_hybrid(rack, seq, NULL, HYBRID_LOG_NO_RANGE, __LINE__, err);
                rc_cur = tcp_req_find_req_for_seq(rack->rc_tp, (seq + len - 1));
        } else {
                err = 12345;
        }
        /* If we find no parameters we are in straight DGP mode */
        if(rc_cur == NULL) {
                /* None found for this seq, just DGP for now */
                if (rack->rc_hybrid_mode) {
                        rack->r_ctl.client_suggested_maxseg = 0;
                        rack->rc_catch_up = 0;
                        if (rack->cspr_is_fcc == 0)
                                rack->r_ctl.bw_rate_cap = 0;
                        else
                                rack->r_ctl.fillcw_cap = rack_fillcw_bw_cap;
                }
                if (rack->rc_hybrid_mode) {
                        rack_log_hybrid(rack, (seq + len - 1), NULL, HYBRID_LOG_NO_RANGE, __LINE__, err);
                }
                if (rack->r_ctl.rc_last_sft) {
                        rack->r_ctl.rc_last_sft = NULL;
                }
                return;
        }
        if ((rc_cur->hybrid_flags & TCP_HYBRID_PACING_WASSET) == 0) {
                /* This entry was never setup for hybrid pacing on/off etc */
                if (rack->rc_hybrid_mode) {
                        rack->r_ctl.client_suggested_maxseg = 0;
                        rack->rc_catch_up = 0;
                        rack->r_ctl.bw_rate_cap = 0;
                }
                if (rack->r_ctl.rc_last_sft) {
                        rack->r_ctl.rc_last_sft = NULL;
                }
                if ((rc_cur->flags & TCP_TRK_TRACK_FLG_FSND) == 0) {
                        rc_cur->flags |= TCP_TRK_TRACK_FLG_FSND;
                        rc_cur->first_send = cts;
                        rc_cur->sent_at_fs = rack->rc_tp->t_sndbytes;
                        rc_cur->rxt_at_fs = rack->rc_tp->t_snd_rxt_bytes;
                }
                return;
        }
        /*
         * Ok if we have a new entry *or* have never
         * set up an entry we need to proceed. If
         * we have already set it up this entry we
         * just continue along with what we already
         * setup.
         */
        tp = rack->rc_tp;
        if ((rack->r_ctl.rc_last_sft != NULL) &&
            (rack->r_ctl.rc_last_sft == rc_cur)) {
                /* Its already in place */
                if (rack->rc_hybrid_mode)
                        rack_log_hybrid(rack, seq, rc_cur, HYBRID_LOG_ISSAME, __LINE__, 0);
                return;
        }
        if (rack->rc_hybrid_mode == 0) {
                rack->r_ctl.rc_last_sft = rc_cur;
                if (orig_ent) {
                        orig_ent->sent_at_ls = rack->rc_tp->t_sndbytes;
                        orig_ent->rxt_at_ls = rack->rc_tp->t_snd_rxt_bytes;
                        orig_ent->flags |= TCP_TRK_TRACK_FLG_LSND;
                }
                rack_log_hybrid(rack, seq, rc_cur, HYBRID_LOG_RULES_APP, __LINE__, 0);
                return;
        }
        if ((rc_cur->hybrid_flags & TCP_HYBRID_PACING_CSPR) && rc_cur->cspr){
                /* Compensate for all the header overhead's */
                if (rack->cspr_is_fcc == 0)
                        rack->r_ctl.bw_rate_cap = rack_compensate_for_linerate(rack, rc_cur->cspr);
                else
                        rack->r_ctl.fillcw_cap =  rack_compensate_for_linerate(rack, rc_cur->cspr);
        } else {
                if (rack->rc_hybrid_mode) {
                        if (rack->cspr_is_fcc == 0)
                                rack->r_ctl.bw_rate_cap = 0;
                        else
                                rack->r_ctl.fillcw_cap = rack_fillcw_bw_cap;
                }
        }
        if (rc_cur->hybrid_flags & TCP_HYBRID_PACING_H_MS)
                rack->r_ctl.client_suggested_maxseg = rc_cur->hint_maxseg;
        else
                rack->r_ctl.client_suggested_maxseg = 0;
        if (rc_cur->timestamp == rack->r_ctl.last_tm_mark) {
                /*
                 * It is the same timestamp as the previous one
                 * add the hybrid flag that will indicate we use
                 * sendtime not arrival time for catch-up mode.
                 */
                rc_cur->hybrid_flags |= TCP_HYBRID_PACING_SENDTIME;
        }
        if ((rc_cur->hybrid_flags & TCP_HYBRID_PACING_CU) &&
            (rc_cur->cspr > 0)) {
                uint64_t len;

                rack->rc_catch_up = 1;
                /*
                 * Calculate the deadline time, first set the
                 * time to when the request arrived.
                 */
                if (rc_cur->hybrid_flags & TCP_HYBRID_PACING_SENDTIME) {
                        /*
                         * For cases where its a duplicate tm (we received more
                         * than one request for a tm) we want to use now, the point
                         * where we are just sending the first bit of the request.
                         */
                        rc_cur->deadline = cts;
                } else {
                        /*
                         * Here we have a different tm from the last request
                         * so we want to use arrival time as our base.
                         */
                        rc_cur->deadline = rc_cur->localtime;
                }
                /*
                 * Next calculate the length and compensate for
                 * TLS if need be.
                 */
                len = rc_cur->end - rc_cur->start;
                if (tp->t_inpcb.inp_socket->so_snd.sb_tls_info) {
                        /*
                         * This session is doing TLS. Take a swag guess
                         * at the overhead.
                         */
                        len += tcp_estimate_tls_overhead(tp->t_inpcb.inp_socket, len);
                }
                /*
                 * Now considering the size, and the cspr, what is the time that
                 * would be required at the cspr rate. Here we use the raw
                 * cspr value since the client only looks at the raw data. We
                 * do use len which includes TLS overhead, but not the TCP/IP etc.
                 * That will get made up for in the CU pacing rate set.
                 */
                len *= HPTS_USEC_IN_SEC;
                len /= rc_cur->cspr;
                rc_cur->deadline += len;
        } else {
                rack->rc_catch_up = 0;
                rc_cur->deadline = 0;
        }
        if (rack->r_ctl.client_suggested_maxseg != 0) {
                /*
                 * We need to reset the max pace segs if we have a
                 * client_suggested_maxseg.
                 */
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
        }
        if (orig_ent) {
                orig_ent->sent_at_ls = rack->rc_tp->t_sndbytes;
                orig_ent->rxt_at_ls = rack->rc_tp->t_snd_rxt_bytes;
                orig_ent->flags |= TCP_TRK_TRACK_FLG_LSND;
        }
        rack_log_hybrid(rack, seq, rc_cur, HYBRID_LOG_RULES_APP, __LINE__, 0);
        /* Remember it for next time and for CU mode */
        rack->r_ctl.rc_last_sft = rc_cur;
        rack->r_ctl.last_tm_mark = rc_cur->timestamp;
}
#endif

static void
rack_chk_req_and_hybrid_on_out(struct tcp_rack *rack, tcp_seq seq, uint32_t len, uint64_t cts)
{
#ifdef TCP_REQUEST_TRK
        struct tcp_sendfile_track *ent;

        ent = rack->r_ctl.rc_last_sft;
        if ((ent == NULL) ||
            (ent->flags == TCP_TRK_TRACK_FLG_EMPTY) ||
            (SEQ_GEQ(seq, ent->end_seq))) {
                /* Time to update the track. */
                rack_set_dgp_hybrid_mode(rack, seq, len, cts);
                ent = rack->r_ctl.rc_last_sft;
        }
        /* Out of all */
        if (ent == NULL) {
                return;
        }
        if (SEQ_LT(ent->end_seq, (seq + len))) {
                /*
                 * This is the case where our end_seq guess
                 * was wrong. This is usually due to TLS having
                 * more bytes then our guess. It could also be the
                 * case that the client sent in two requests closely
                 * and the SB is full of both so we are sending part
                 * of each (end|beg). In such a case lets move this
                 * guys end to match the end of this send. That
                 * way it will complete when all of it is acked.
                 */
                ent->end_seq = (seq + len);
                if (rack->rc_hybrid_mode)
                        rack_log_hybrid_bw(rack, seq, len, 0, 0, HYBRID_LOG_EXTEND, 0, ent, __LINE__);
        }
        /* Now validate we have set the send time of this one */
        if ((ent->flags & TCP_TRK_TRACK_FLG_FSND) == 0) {
                ent->flags |= TCP_TRK_TRACK_FLG_FSND;
                ent->first_send = cts;
                ent->sent_at_fs = rack->rc_tp->t_sndbytes;
                ent->rxt_at_fs = rack->rc_tp->t_snd_rxt_bytes;
        }
#endif
}

static void
rack_gain_for_fastoutput(struct tcp_rack *rack, struct tcpcb *tp, struct socket *so, uint32_t acked_amount)
{
        /*
         * The fast output path is enabled and we
         * have moved the cumack forward. Lets see if
         * we can expand forward the fast path length by
         * that amount. What we would ideally like to
         * do is increase the number of bytes in the
         * fast path block (left_to_send) by the
         * acked amount. However we have to gate that
         * by two factors:
         * 1) The amount outstanding and the rwnd of the peer
         *    (i.e. we don't want to exceed the rwnd of the peer).
         *    <and>
         * 2) The amount of data left in the socket buffer (i.e.
         *    we can't send beyond what is in the buffer).
         *
         * Note that this does not take into account any increase
         * in the cwnd. We will only extend the fast path by
         * what was acked.
         */
        uint32_t new_total, gating_val;

        new_total = acked_amount + rack->r_ctl.fsb.left_to_send;
        gating_val = min((sbavail(&so->so_snd) - (tp->snd_max - tp->snd_una)),
                         (tp->snd_wnd - (tp->snd_max - tp->snd_una)));
        if (new_total <= gating_val) {
                /* We can increase left_to_send by the acked amount */
                counter_u64_add(rack_extended_rfo, 1);
                rack->r_ctl.fsb.left_to_send = new_total;
                KASSERT((rack->r_ctl.fsb.left_to_send <= (sbavail(&rack->rc_inp->inp_socket->so_snd) - (tp->snd_max - tp->snd_una))),
                        ("rack:%p left_to_send:%u sbavail:%u out:%u",
                         rack, rack->r_ctl.fsb.left_to_send,
                         sbavail(&rack->rc_inp->inp_socket->so_snd),
                         (tp->snd_max - tp->snd_una)));

        }
}

static void
rack_adjust_sendmap_head(struct tcp_rack *rack, struct sockbuf *sb)
{
        /*
         * Here any sendmap entry that points to the
         * beginning mbuf must be adjusted to the correct
         * offset. This must be called with:
         * 1) The socket buffer locked
         * 2) snd_una adjusted to its new position.
         *
         * Note that (2) implies rack_ack_received has also
         * been called and all the sbcut's have been done.
         *
         * We grab the first mbuf in the socket buffer and
         * then go through the front of the sendmap, recalculating
         * the stored offset for any sendmap entry that has
         * that mbuf. We must use the sb functions to do this
         * since its possible an add was done has well as
         * the subtraction we may have just completed. This should
         * not be a penalty though, since we just referenced the sb
         * to go in and trim off the mbufs that we freed (of course
         * there will be a penalty for the sendmap references though).
         *
         * Note also with INVARIANT on, we validate with a KASSERT
         * that the first sendmap entry has a soff of 0.
         *
         */
        struct mbuf *m;
        struct rack_sendmap *rsm;
        tcp_seq snd_una;
#ifdef INVARIANTS
        int first_processed = 0;
#endif

        snd_una = rack->rc_tp->snd_una;
        SOCKBUF_LOCK_ASSERT(sb);
        m = sb->sb_mb;
        rsm = tqhash_min(rack->r_ctl.tqh);
        if ((rsm == NULL) || (m == NULL)) {
                /* Nothing outstanding */
                return;
        }
        /* The very first RSM's mbuf must point to the head mbuf in the sb */
        KASSERT((rsm->m == m),
                ("Rack:%p sb:%p rsm:%p -- first rsm mbuf not aligned to sb",
                 rack, sb, rsm));
        while (rsm->m && (rsm->m == m)) {
                /* one to adjust */
#ifdef INVARIANTS
                struct mbuf *tm;
                uint32_t soff;

                tm = sbsndmbuf(sb, (rsm->r_start - snd_una), &soff);
                if ((rsm->orig_m_len != m->m_len) ||
                    (rsm->orig_t_space != M_TRAILINGROOM(m))){
                        rack_adjust_orig_mlen(rsm);
                }
                if (first_processed == 0) {
                        KASSERT((rsm->soff == 0),
                                ("Rack:%p rsm:%p -- rsm at head but soff not zero",
                                 rack, rsm));
                        first_processed = 1;
                }
                if ((rsm->soff != soff) || (rsm->m != tm)) {
                        /*
                         * This is not a fatal error, we anticipate it
                         * might happen (the else code), so we count it here
                         * so that under invariant we can see that it really
                         * does happen.
                         */
                        counter_u64_add(rack_adjust_map_bw, 1);
                }
                rsm->m = tm;
                rsm->soff = soff;
                if (tm) {
                        rsm->orig_m_len = rsm->m->m_len;
                        rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                } else {
                        rsm->orig_m_len = 0;
                        rsm->orig_t_space = 0;
                }
#else
                rsm->m = sbsndmbuf(sb, (rsm->r_start - snd_una), &rsm->soff);
                if (rsm->m) {
                        rsm->orig_m_len = rsm->m->m_len;
                        rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                } else {
                        rsm->orig_m_len = 0;
                        rsm->orig_t_space = 0;
                }
#endif
                rsm = tqhash_next(rack->r_ctl.tqh, rsm);
                if (rsm == NULL)
                        break;
        }
}

#ifdef TCP_REQUEST_TRK
static inline void
rack_req_check_for_comp(struct tcp_rack *rack, tcp_seq th_ack)
{
        struct tcp_sendfile_track *ent;
        int i;

        if ((rack->rc_hybrid_mode == 0) &&
            (tcp_bblogging_point_on(rack->rc_tp, TCP_BBPOINT_REQ_LEVEL_LOGGING) == 0)) {
                /*
                 * Just do normal completions hybrid pacing is not on
                 * and CLDL is off as well.
                 */
                tcp_req_check_for_comp(rack->rc_tp, th_ack);
                return;
        }
        /*
         * Originally I was just going to find the th_ack associated
         * with an entry. But then I realized a large strech ack could
         * in theory ack two or more requests at once. So instead we
         * need to find all entries that are completed by th_ack not
         * just a single entry and do our logging.
         */
        ent = tcp_req_find_a_req_that_is_completed_by(rack->rc_tp, th_ack, &i);
        while (ent != NULL) {
                /*
                 * We may be doing hybrid pacing or CLDL and need more details possibly
                 * so we do it manually instead of calling
                 * tcp_req_check_for_comp()
                 */
                uint64_t laa, tim, data, cbw, ftim;

                /* Ok this ack frees it */
                rack_log_hybrid(rack, th_ack,
                                ent, HYBRID_LOG_REQ_COMP, __LINE__, 0);
                rack_log_hybrid_sends(rack, ent, __LINE__);
                /* calculate the time based on the ack arrival */
                data = ent->end - ent->start;
                laa = tcp_tv_to_lusec(&rack->r_ctl.act_rcv_time);
                if (ent->flags & TCP_TRK_TRACK_FLG_FSND) {
                        if (ent->first_send > ent->localtime)
                                ftim = ent->first_send;
                        else
                                ftim = ent->localtime;
                } else {
                        /* TSNH */
                        ftim = ent->localtime;
                }
                if (laa > ent->localtime)
                        tim = laa - ftim;
                else
                        tim = 0;
                cbw = data * HPTS_USEC_IN_SEC;
                if (tim > 0)
                        cbw /= tim;
                else
                        cbw = 0;
                rack_log_hybrid_bw(rack, th_ack, cbw, tim, data, HYBRID_LOG_BW_MEASURE, 0, ent, __LINE__);
                /*
                 * Check to see if we are freeing what we are pointing to send wise
                 * if so be sure to NULL the pointer so we know we are no longer
                 * set to anything.
                 */
                if (ent == rack->r_ctl.rc_last_sft) {
                        rack->r_ctl.rc_last_sft = NULL;
                        if (rack->rc_hybrid_mode) {
                                rack->rc_catch_up = 0;
                                if (rack->cspr_is_fcc == 0)
                                        rack->r_ctl.bw_rate_cap = 0;
                                else
                                        rack->r_ctl.fillcw_cap = rack_fillcw_bw_cap;
                                rack->r_ctl.client_suggested_maxseg = 0;
                        }
                }
                /* Generate the log that the tcp_netflix call would have */
                tcp_req_log_req_info(rack->rc_tp, ent,
                                      i, TCP_TRK_REQ_LOG_FREED, 0, 0);
                /* Free it and see if there is another one */
                tcp_req_free_a_slot(rack->rc_tp, ent);
                ent = tcp_req_find_a_req_that_is_completed_by(rack->rc_tp, th_ack, &i);
        }
}
#endif


/*
 * Return value of 1, we do not need to call rack_process_data().
 * return value of 0, rack_process_data can be called.
 * For ret_val if its 0 the TCP is locked, if its non-zero
 * its unlocked and probably unsafe to touch the TCB.
 */
static int
rack_process_ack(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to,
    uint32_t tiwin, int32_t tlen,
    int32_t * ofia, int32_t thflags, int32_t *ret_val, int32_t orig_tlen)
{
        int32_t ourfinisacked = 0;
        int32_t nsegs, acked_amount;
        int32_t acked;
        struct mbuf *mfree;
        struct tcp_rack *rack;
        int32_t under_pacing = 0;
        int32_t post_recovery = 0;
        uint32_t p_cwnd;

        INP_WLOCK_ASSERT(tptoinpcb(tp));

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (SEQ_GEQ(tp->snd_una, tp->iss + (65535 << tp->snd_scale))) {
                /* Checking SEG.ACK against ISS is definitely redundant. */
                tp->t_flags2 |= TF2_NO_ISS_CHECK;
        }
        if (!V_tcp_insecure_ack) {
                tcp_seq seq_min;
                bool ghost_ack_check;

                if (tp->t_flags2 & TF2_NO_ISS_CHECK) {
                        /* Check for too old ACKs (RFC 5961, Section 5.2). */
                        seq_min = tp->snd_una - tp->max_sndwnd;
                        ghost_ack_check = false;
                } else {
                        if (SEQ_GT(tp->iss + 1, tp->snd_una - tp->max_sndwnd)) {
                                /* Checking for ghost ACKs is stricter. */
                                seq_min = tp->iss + 1;
                                ghost_ack_check = true;
                        } else {
                                /*
                                 * Checking for too old ACKs (RFC 5961,
                                 * Section 5.2) is stricter.
                                 */
                                seq_min = tp->snd_una - tp->max_sndwnd;
                                ghost_ack_check = false;
                        }
                }
                if (SEQ_LT(th->th_ack, seq_min)) {
                        if (ghost_ack_check)
                                TCPSTAT_INC(tcps_rcvghostack);
                        else
                                TCPSTAT_INC(tcps_rcvacktooold);
                        /* Send challenge ACK. */
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val);
                        rack->r_wanted_output = 1;
                        return (1);
                }
        }
        if (SEQ_GT(th->th_ack, tp->snd_max)) {
                ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val);
                rack->r_wanted_output = 1;
                return (1);
        }
        if (rack->gp_ready &&
            (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT)) {
                under_pacing = 1;
        }
        if (SEQ_GEQ(th->th_ack, tp->snd_una) || to->to_nsacks) {
                int in_rec, dup_ack_struck = 0;
                int dsack_seen = 0, sacks_seen = 0;

                in_rec = IN_FASTRECOVERY(tp->t_flags);
                if (rack->rc_in_persist) {
                        tp->t_rxtshift = 0;
                        RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                                      rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
                }

                if ((th->th_ack == tp->snd_una) &&
                    (tiwin == tp->snd_wnd) &&
                    (orig_tlen == 0) &&
                    ((to->to_flags & TOF_SACK) == 0)) {
                        rack_strike_dupack(rack, th->th_ack);
                        dup_ack_struck = 1;
                }
                rack_log_ack(tp, to, th, ((in_rec == 0) && IN_FASTRECOVERY(tp->t_flags)),
                             dup_ack_struck, &dsack_seen, &sacks_seen);

        }
        if (__predict_false(SEQ_LEQ(th->th_ack, tp->snd_una))) {
                /*
                 * Old ack, behind (or duplicate to) the last one rcv'd
                 * Note: We mark reordering is occuring if its
                 * less than and we have not closed our window.
                 */
                if (SEQ_LT(th->th_ack, tp->snd_una) && (sbspace(&so->so_rcv) > ctf_fixed_maxseg(tp))) {
                        rack->r_ctl.rc_reorder_ts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
                        if (rack->r_ctl.rc_reorder_ts == 0)
                                rack->r_ctl.rc_reorder_ts = 1;
                }
                return (0);
        }
        /*
         * If we reach this point, ACK is not a duplicate, i.e., it ACKs
         * something we sent.
         */
        if (tp->t_flags & TF_NEEDSYN) {
                /*
                 * T/TCP: Connection was half-synchronized, and our SYN has
                 * been ACK'd (so connection is now fully synchronized).  Go
                 * to non-starred state, increment snd_una for ACK of SYN,
                 * and check if we can do window scaling.
                 */
                tp->t_flags &= ~TF_NEEDSYN;
                tp->snd_una++;
                /* Do window scaling? */
                if ((tp->t_flags & (TF_RCVD_SCALE | TF_REQ_SCALE)) ==
                    (TF_RCVD_SCALE | TF_REQ_SCALE)) {
                        tp->rcv_scale = tp->request_r_scale;
                        /* Send window already scaled. */
                }
        }
        nsegs = max(1, m->m_pkthdr.lro_nsegs);

        acked = BYTES_THIS_ACK(tp, th);
        if (acked) {
                /*
                 * Any time we move the cum-ack forward clear
                 * keep-alive tied probe-not-answered. The
                 * persists clears its own on entry.
                 */
                rack->probe_not_answered = 0;
        }
        KMOD_TCPSTAT_ADD(tcps_rcvackpack, nsegs);
        KMOD_TCPSTAT_ADD(tcps_rcvackbyte, acked);
        /*
         * If we just performed our first retransmit, and the ACK arrives
         * within our recovery window, then it was a mistake to do the
         * retransmit in the first place.  Recover our original cwnd and
         * ssthresh, and proceed to transmit where we left off.
         */
        if ((tp->t_flags & TF_PREVVALID) &&
            ((tp->t_flags & TF_RCVD_TSTMP) == 0)) {
                tp->t_flags &= ~TF_PREVVALID;
                if (tp->t_rxtshift == 1 &&
                    (int)(ticks - tp->t_badrxtwin) < 0)
                        rack_cong_signal(tp, CC_RTO_ERR, th->th_ack, __LINE__);
        }
        if (acked) {
                /* assure we are not backed off */
                tp->t_rxtshift = 0;
                RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                              rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
                rack->rc_tlp_in_progress = 0;
                rack->r_ctl.rc_tlp_cnt_out = 0;
                /*
                 * If it is the RXT timer we want to
                 * stop it, so we can restart a TLP.
                 */
                if (rack->r_ctl.rc_hpts_flags & PACE_TMR_RXT)
                        rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
#ifdef TCP_REQUEST_TRK
                rack_req_check_for_comp(rack, th->th_ack);
#endif
        }
        /*
         * If we have a timestamp reply, update smoothed round trip time. If
         * no timestamp is present but transmit timer is running and timed
         * sequence number was acked, update smoothed round trip time. Since
         * we now have an rtt measurement, cancel the timer backoff (cf.,
         * Phil Karn's retransmit alg.). Recompute the initial retransmit
         * timer.
         *
         * Some boxes send broken timestamp replies during the SYN+ACK
         * phase, ignore timestamps of 0 or we could calculate a huge RTT
         * and blow up the retransmit timer.
         */
        /*
         * If all outstanding data is acked, stop retransmit timer and
         * remember to restart (more output or persist). If there is more
         * data to be acked, restart retransmit timer, using current
         * (possibly backed-off) value.
         */
        if (acked == 0) {
                if (ofia)
                        *ofia = ourfinisacked;
                return (0);
        }
        if (IN_RECOVERY(tp->t_flags)) {
                if (SEQ_LT(th->th_ack, tp->snd_recover) &&
                    (SEQ_LT(th->th_ack, tp->snd_max))) {
                        tcp_rack_partialack(tp);
                } else {
                        rack_post_recovery(tp, th->th_ack);
                        post_recovery = 1;
                        /*
                         * Grab the segsiz, multiply by 2 and add the snd_cwnd
                         * that is the max the CC should add if we are exiting
                         * recovery and doing a late add.
                         */
                        p_cwnd = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
                        p_cwnd <<= 1;
                        p_cwnd += tp->snd_cwnd;
                }
        } else if ((rack->rto_from_rec == 1) &&
                   SEQ_GEQ(th->th_ack, tp->snd_recover)) {
                /*
                 * We were in recovery, hit a rxt timeout
                 * and never re-entered recovery. The timeout(s)
                 * made up all the lost data. In such a case
                 * we need to clear the rto_from_rec flag.
                 */
                rack->rto_from_rec = 0;
        }
        /*
         * Let the congestion control algorithm update congestion control
         * related information. This typically means increasing the
         * congestion window.
         */
        rack_ack_received(tp, rack, th->th_ack, nsegs, CC_ACK, post_recovery);
        if (post_recovery &&
            (tp->snd_cwnd > p_cwnd)) {
                /* Must be non-newreno (cubic) getting too ahead of itself */
                tp->snd_cwnd = p_cwnd;
        }
        SOCK_SENDBUF_LOCK(so);
        acked_amount = min(acked, (int)sbavail(&so->so_snd));
        tp->snd_wnd -= acked_amount;
        mfree = sbcut_locked(&so->so_snd, acked_amount);
        if ((sbused(&so->so_snd) == 0) &&
            (acked > acked_amount) &&
            (tp->t_state >= TCPS_FIN_WAIT_1) &&
            (tp->t_flags & TF_SENTFIN)) {
                /*
                 * We must be sure our fin
                 * was sent and acked (we can be
                 * in FIN_WAIT_1 without having
                 * sent the fin).
                 */
                ourfinisacked = 1;
        }
        tp->snd_una = th->th_ack;
        /* wakeups? */
        if (acked_amount && sbavail(&so->so_snd))
                rack_adjust_sendmap_head(rack, &so->so_snd);
        rack_log_wakeup(tp,rack, &so->so_snd, acked, 2);
        /* NB: sowwakeup_locked() does an implicit unlock. */
        sowwakeup_locked(so);
        m_freem(mfree);
        if (SEQ_GT(tp->snd_una, tp->snd_recover))
                tp->snd_recover = tp->snd_una;

        if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
                tp->snd_nxt = tp->snd_max;
        }
        if (under_pacing &&
            (rack->use_fixed_rate == 0) &&
            (rack->in_probe_rtt == 0) &&
            rack->rc_gp_dyn_mul &&
            rack->rc_always_pace) {
                /* Check if we are dragging bottom */
                rack_check_bottom_drag(tp, rack, so);
        }
        if (tp->snd_una == tp->snd_max) {
                /* Nothing left outstanding */
                tp->t_flags &= ~TF_PREVVALID;
                if (rack->r_ctl.rc_went_idle_time == 0)
                        rack->r_ctl.rc_went_idle_time = 1;
                rack->r_ctl.retran_during_recovery = 0;
                rack->r_ctl.dsack_byte_cnt = 0;
                rack_log_progress_event(rack, tp, 0, PROGRESS_CLEAR, __LINE__);
                if (sbavail(&tptosocket(tp)->so_snd) == 0)
                        tp->t_acktime = 0;
                rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
                rack->rc_suspicious = 0;
                /* Set need output so persist might get set */
                rack->r_wanted_output = 1;
                sack_filter_clear(&rack->r_ctl.rack_sf, tp->snd_una);
                if ((tp->t_state >= TCPS_FIN_WAIT_1) &&
                    (sbavail(&so->so_snd) == 0) &&
                    (tp->t_flags2 & TF2_DROP_AF_DATA)) {
                        /*
                         * The socket was gone and the
                         * peer sent data (now or in the past), time to
                         * reset him.
                         */
                        *ret_val = 1;
                        /* tcp_close will kill the inp pre-log the Reset */
                        tcp_log_end_status(tp, TCP_EI_STATUS_SERVER_RST);
                        tp = tcp_close(tp);
                        ctf_do_dropwithreset(m, tp, th, tlen);
                        return (1);
                }
        }
        if (ofia)
                *ofia = ourfinisacked;
        return (0);
}


static void
rack_log_collapse(struct tcp_rack *rack, uint32_t cnt, uint32_t split, uint32_t out, int line,
                  int dir, uint32_t flags, struct rack_sendmap *rsm)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = cnt;
                log.u_bbr.flex2 = split;
                log.u_bbr.flex3 = out;
                log.u_bbr.flex4 = line;
                log.u_bbr.flex5 = rack->r_must_retran;
                log.u_bbr.flex6 = flags;
                log.u_bbr.flex7 = rack->rc_has_collapsed;
                log.u_bbr.flex8 = dir;  /*
                                         * 1 is collapsed, 0 is uncollapsed,
                                         * 2 is log of a rsm being marked, 3 is a split.
                                         */
                if (rsm == NULL)
                        log.u_bbr.rttProp = 0;
                else
                        log.u_bbr.rttProp = (uintptr_t)rsm;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    TCP_RACK_LOG_COLLAPSE, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_collapsed_window(struct tcp_rack *rack, uint32_t out, tcp_seq th_ack, int line)
{
        /*
         * Here all we do is mark the collapsed point and set the flag.
         * This may happen again and again, but there is no
         * sense splitting our map until we know where the
         * peer finally lands in the collapse.
         */
        tcp_trace_point(rack->rc_tp, TCP_TP_COLLAPSED_WND);
        if ((rack->rc_has_collapsed == 0) ||
            (rack->r_ctl.last_collapse_point != (th_ack + rack->rc_tp->snd_wnd)))
                counter_u64_add(rack_collapsed_win_seen, 1);
        rack->r_ctl.last_collapse_point = th_ack + rack->rc_tp->snd_wnd;
        rack->r_ctl.high_collapse_point = rack->rc_tp->snd_max;
        rack->rc_has_collapsed = 1;
        rack->r_collapse_point_valid = 1;
        rack_log_collapse(rack, 0, th_ack, rack->r_ctl.last_collapse_point, line, 1, 0, NULL);
}

static void
rack_un_collapse_window(struct tcp_rack *rack, int line)
{
        struct rack_sendmap *nrsm, *rsm;
        int cnt = 0, split = 0;
        int insret __diagused;


        tcp_trace_point(rack->rc_tp, TCP_TP_COLLAPSED_WND);
        rack->rc_has_collapsed = 0;
        rsm = tqhash_find(rack->r_ctl.tqh, rack->r_ctl.last_collapse_point);
        if (rsm == NULL) {
                /* Nothing to do maybe the peer ack'ed it all */
                rack_log_collapse(rack, 0, 0, ctf_outstanding(rack->rc_tp), line, 0, 0, NULL);
                return;
        }
        /* Now do we need to split this one? */
        if (SEQ_GT(rack->r_ctl.last_collapse_point, rsm->r_start)) {
                rack_log_collapse(rack, rsm->r_start, rsm->r_end,
                                  rack->r_ctl.last_collapse_point, line, 3, rsm->r_flags, rsm);
                nrsm = rack_alloc_limit(rack, RACK_LIMIT_TYPE_SPLIT);
                if (nrsm == NULL) {
                        /* We can't get a rsm, mark all? */
                        nrsm = rsm;
                        goto no_split;
                }
                /* Clone it */
                split = 1;
                rack_clone_rsm(rack, nrsm, rsm, rack->r_ctl.last_collapse_point);
#ifndef INVARIANTS
                (void)tqhash_insert(rack->r_ctl.tqh, nrsm);
#else
                if ((insret = tqhash_insert(rack->r_ctl.tqh, nrsm)) != 0) {
                        panic("Insert in tailq_hash of %p fails ret:%d rack:%p rsm:%p",
                              nrsm, insret, rack, rsm);
                }
#endif
                rack_log_map_chg(rack->rc_tp, rack, NULL, rsm, nrsm, MAP_SPLIT,
                                 rack->r_ctl.last_collapse_point, __LINE__);
                if (rsm->r_in_tmap) {
                        TAILQ_INSERT_AFTER(&rack->r_ctl.rc_tmap, rsm, nrsm, r_tnext);
                        nrsm->r_in_tmap = 1;
                }
                /*
                 * Set in the new RSM as the
                 * collapsed starting point
                 */
                rsm = nrsm;
        }

no_split:
        TQHASH_FOREACH_FROM(nrsm, rack->r_ctl.tqh, rsm)  {
                cnt++;
                nrsm->r_flags |= RACK_RWND_COLLAPSED;
                rack_log_collapse(rack, nrsm->r_start, nrsm->r_end, 0, line, 4, nrsm->r_flags, nrsm);
                cnt++;
        }
        if (cnt) {
                counter_u64_add(rack_collapsed_win, 1);
        }
        rack_log_collapse(rack, cnt, split, ctf_outstanding(rack->rc_tp), line, 0, 0, NULL);
}

static void
rack_handle_delayed_ack(struct tcpcb *tp, struct tcp_rack *rack,
                        int32_t tlen, int32_t tfo_syn)
{
        if (DELAY_ACK(tp, tlen) || tfo_syn) {
                rack_timer_cancel(tp, rack,
                                  rack->r_ctl.rc_rcvtime, __LINE__);
                tp->t_flags |= TF_DELACK;
        } else {
                rack->r_wanted_output = 1;
                tp->t_flags |= TF_ACKNOW;
        }
}

static void
rack_validate_fo_sendwin_up(struct tcpcb *tp, struct tcp_rack *rack)
{
        /*
         * If fast output is in progress, lets validate that
         * the new window did not shrink on us and make it
         * so fast output should end.
         */
        if (rack->r_fast_output) {
                uint32_t out;

                /*
                 * Calculate what we will send if left as is
                 * and compare that to our send window.
                 */
                out = ctf_outstanding(tp);
                if ((out + rack->r_ctl.fsb.left_to_send) > tp->snd_wnd) {
                        /* ok we have an issue */
                        if (out >= tp->snd_wnd) {
                                /* Turn off fast output the window is met or collapsed */
                                rack->r_fast_output = 0;
                        } else {
                                /* we have some room left */
                                rack->r_ctl.fsb.left_to_send = tp->snd_wnd - out;
                                if (rack->r_ctl.fsb.left_to_send < ctf_fixed_maxseg(tp)) {
                                        /* If not at least 1 full segment never mind */
                                        rack->r_fast_output = 0;
                                }
                        }
                }
        }
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_process_data(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt)
{
        /*
         * Update window information. Don't look at window if no ACK: TAC's
         * send garbage on first SYN.
         */
        int32_t nsegs;
        int32_t tfo_syn;
        struct tcp_rack *rack;

        INP_WLOCK_ASSERT(tptoinpcb(tp));

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        nsegs = max(1, m->m_pkthdr.lro_nsegs);
        if ((thflags & TH_ACK) &&
            (SEQ_LT(tp->snd_wl1, th->th_seq) ||
            (tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) ||
            (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) {
                /* keep track of pure window updates */
                if (tlen == 0 &&
                    tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
                        KMOD_TCPSTAT_INC(tcps_rcvwinupd);
                tp->snd_wnd = tiwin;
                rack_validate_fo_sendwin_up(tp, rack);
                tp->snd_wl1 = th->th_seq;
                tp->snd_wl2 = th->th_ack;
                if (tp->snd_wnd > tp->max_sndwnd)
                        tp->max_sndwnd = tp->snd_wnd;
                rack->r_wanted_output = 1;
        } else if (thflags & TH_ACK) {
                if ((tp->snd_wl2 == th->th_ack) && (tiwin < tp->snd_wnd)) {
                        tp->snd_wnd = tiwin;
                        rack_validate_fo_sendwin_up(tp, rack);
                        tp->snd_wl1 = th->th_seq;
                        tp->snd_wl2 = th->th_ack;
                }
        }
        if (tp->snd_wnd < ctf_outstanding(tp))
                /* The peer collapsed the window */
                rack_collapsed_window(rack, ctf_outstanding(tp), th->th_ack, __LINE__);
        else if (rack->rc_has_collapsed)
                rack_un_collapse_window(rack, __LINE__);
        if ((rack->r_collapse_point_valid) &&
            (SEQ_GT(th->th_ack, rack->r_ctl.high_collapse_point)))
                rack->r_collapse_point_valid = 0;
        /* Was persist timer active and now we have window space? */
        if ((rack->rc_in_persist != 0) &&
            (tp->snd_wnd >= min((rack->r_ctl.rc_high_rwnd/2),
                                rack->r_ctl.rc_pace_min_segs))) {
                rack_exit_persist(tp, rack, rack->r_ctl.rc_rcvtime);
                tp->snd_nxt = tp->snd_max;
                /* Make sure we output to start the timer */
                rack->r_wanted_output = 1;
        }
        /* Do we enter persists? */
        if ((rack->rc_in_persist == 0) &&
            (tp->snd_wnd < min((rack->r_ctl.rc_high_rwnd/2), rack->r_ctl.rc_pace_min_segs)) &&
            TCPS_HAVEESTABLISHED(tp->t_state) &&
            ((tp->snd_max == tp->snd_una) || rack->rc_has_collapsed) &&
            sbavail(&tptosocket(tp)->so_snd) &&
            (sbavail(&tptosocket(tp)->so_snd) > tp->snd_wnd)) {
                /*
                 * Here the rwnd is less than
                 * the pacing size, we are established,
                 * nothing is outstanding, and there is
                 * data to send. Enter persists.
                 */
                rack_enter_persist(tp, rack, rack->r_ctl.rc_rcvtime, tp->snd_una);
        }
        if (tp->t_flags2 & TF2_DROP_AF_DATA) {
                m_freem(m);
                return (0);
        }
        /*
         * don't process the URG bit, ignore them drag
         * along the up.
         */
        tp->rcv_up = tp->rcv_nxt;

        /*
         * Process the segment text, merging it into the TCP sequencing
         * queue, and arranging for acknowledgment of receipt if necessary.
         * This process logically involves adjusting tp->rcv_wnd as data is
         * presented to the user (this happens in tcp_usrreq.c, case
         * PRU_RCVD).  If a FIN has already been received on this connection
         * then we just ignore the text.
         */
        tfo_syn = ((tp->t_state == TCPS_SYN_RECEIVED) &&
            (tp->t_flags & TF_FASTOPEN));
        if ((tlen || (thflags & TH_FIN) || (tfo_syn && tlen > 0)) &&
            TCPS_HAVERCVDFIN(tp->t_state) == 0) {
                tcp_seq save_start = th->th_seq;
                tcp_seq save_rnxt  = tp->rcv_nxt;
                int     save_tlen  = tlen;

                m_adj(m, drop_hdrlen);  /* delayed header drop */
                /*
                 * Insert segment which includes th into TCP reassembly
                 * queue with control block tp.  Set thflags to whether
                 * reassembly now includes a segment with FIN.  This handles
                 * the common case inline (segment is the next to be
                 * received on an established connection, and the queue is
                 * empty), avoiding linkage into and removal from the queue
                 * and repetition of various conversions. Set DELACK for
                 * segments received in order, but ack immediately when
                 * segments are out of order (so fast retransmit can work).
                 */
                if (th->th_seq == tp->rcv_nxt &&
                    SEGQ_EMPTY(tp) &&
                    (TCPS_HAVEESTABLISHED(tp->t_state) ||
                    tfo_syn)) {
#ifdef NETFLIX_SB_LIMITS
                        u_int mcnt, appended;

                        if (so->so_rcv.sb_shlim) {
                                mcnt = m_memcnt(m);
                                appended = 0;
                                if (counter_fo_get(so->so_rcv.sb_shlim, mcnt,
                                    CFO_NOSLEEP, NULL) == false) {
                                        counter_u64_add(tcp_sb_shlim_fails, 1);
                                        m_freem(m);
                                        return (0);
                                }
                        }
#endif
                        rack_handle_delayed_ack(tp, rack, tlen, tfo_syn);
                        tp->rcv_nxt += tlen;
                        if (tlen &&
                            ((tp->t_flags2 & TF2_FBYTES_COMPLETE) == 0) &&
                            (tp->t_fbyte_in == 0)) {
                                tp->t_fbyte_in = ticks;
                                if (tp->t_fbyte_in == 0)
                                        tp->t_fbyte_in = 1;
                                if (tp->t_fbyte_out && tp->t_fbyte_in)
                                        tp->t_flags2 |= TF2_FBYTES_COMPLETE;
                        }
                        thflags = tcp_get_flags(th) & TH_FIN;
                        KMOD_TCPSTAT_ADD(tcps_rcvpack, nsegs);
                        KMOD_TCPSTAT_ADD(tcps_rcvbyte, tlen);
                        SOCK_RECVBUF_LOCK(so);
                        if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                                m_freem(m);
                        } else {
                                int32_t newsize;

                                if (tlen > 0) {
                                        newsize = tcp_autorcvbuf(m, th, so, tp, tlen);
                                        if (newsize)
                                                if (!sbreserve_locked(so, SO_RCV, newsize, NULL))
                                                        so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
                                }
#ifdef NETFLIX_SB_LIMITS
                                appended =
#endif
                                        sbappendstream_locked(&so->so_rcv, m, 0);
                        }
                        rack_log_wakeup(tp,rack, &so->so_rcv, tlen, 1);
                        /* NB: sorwakeup_locked() does an implicit unlock. */
                        sorwakeup_locked(so);
#ifdef NETFLIX_SB_LIMITS
                        if (so->so_rcv.sb_shlim && appended != mcnt)
                                counter_fo_release(so->so_rcv.sb_shlim,
                                    mcnt - appended);
#endif
                } else {
                        /*
                         * XXX: Due to the header drop above "th" is
                         * theoretically invalid by now.  Fortunately
                         * m_adj() doesn't actually frees any mbufs when
                         * trimming from the head.
                         */
                        tcp_seq temp = save_start;

                        thflags = tcp_reass(tp, th, &temp, &tlen, m);
                        tp->t_flags |= TF_ACKNOW;
                        if (tp->t_flags & TF_WAKESOR) {
                                tp->t_flags &= ~TF_WAKESOR;
                                /* NB: sorwakeup_locked() does an implicit unlock. */
                                sorwakeup_locked(so);
                        }
                }
                if ((tp->t_flags & TF_SACK_PERMIT) &&
                    (save_tlen > 0) &&
                    TCPS_HAVEESTABLISHED(tp->t_state)) {
                        if ((tlen == 0) && (SEQ_LT(save_start, save_rnxt))) {
                                /*
                                 * DSACK actually handled in the fastpath
                                 * above.
                                 */
                                tcp_update_sack_list(tp, save_start,
                                    save_start + save_tlen);
                        } else if ((tlen > 0) && SEQ_GT(tp->rcv_nxt, save_rnxt)) {
                                if ((tp->rcv_numsacks >= 1) &&
                                    (tp->sackblks[0].end == save_start)) {
                                        /*
                                         * Partial overlap, recorded at todrop
                                         * above.
                                         */
                                        tcp_update_sack_list(tp,
                                            tp->sackblks[0].start,
                                            tp->sackblks[0].end);
                                } else {
                                        tcp_update_dsack_list(tp, save_start,
                                            save_start + save_tlen);
                                }
                        } else if (tlen >= save_tlen) {
                                /* Update of sackblks. */
                                tcp_update_dsack_list(tp, save_start,
                                    save_start + save_tlen);
                        } else if (tlen > 0) {
                                tcp_update_dsack_list(tp, save_start,
                                    save_start + tlen);
                        }
                }
        } else {
                m_freem(m);
                thflags &= ~TH_FIN;
        }

        /*
         * If FIN is received ACK the FIN and let the user know that the
         * connection is closing.
         */
        if (thflags & TH_FIN) {
                if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
                        /* The socket upcall is handled by socantrcvmore. */
                        socantrcvmore(so);
                        /*
                         * If connection is half-synchronized (ie NEEDSYN
                         * flag on) then delay ACK, so it may be piggybacked
                         * when SYN is sent. Otherwise, since we received a
                         * FIN then no more input can be expected, send ACK
                         * now.
                         */
                        if (tp->t_flags & TF_NEEDSYN) {
                                rack_timer_cancel(tp, rack,
                                    rack->r_ctl.rc_rcvtime, __LINE__);
                                tp->t_flags |= TF_DELACK;
                        } else {
                                tp->t_flags |= TF_ACKNOW;
                        }
                        tp->rcv_nxt++;
                }
                switch (tp->t_state) {
                        /*
                         * In SYN_RECEIVED and ESTABLISHED STATES enter the
                         * CLOSE_WAIT state.
                         */
                case TCPS_SYN_RECEIVED:
                        tp->t_starttime = ticks;
                        /* FALLTHROUGH */
                case TCPS_ESTABLISHED:
                        rack_timer_cancel(tp, rack,
                            rack->r_ctl.rc_rcvtime, __LINE__);
                        tcp_state_change(tp, TCPS_CLOSE_WAIT);
                        break;

                        /*
                         * If still in FIN_WAIT_1 STATE FIN has not been
                         * acked so enter the CLOSING state.
                         */
                case TCPS_FIN_WAIT_1:
                        rack_timer_cancel(tp, rack,
                            rack->r_ctl.rc_rcvtime, __LINE__);
                        tcp_state_change(tp, TCPS_CLOSING);
                        break;

                        /*
                         * In FIN_WAIT_2 state enter the TIME_WAIT state,
                         * starting the time-wait timer, turning off the
                         * other standard timers.
                         */
                case TCPS_FIN_WAIT_2:
                        rack_timer_cancel(tp, rack,
                            rack->r_ctl.rc_rcvtime, __LINE__);
                        tcp_twstart(tp);
                        return (1);
                }
        }
        /*
         * Return any desired output.
         */
        if ((tp->t_flags & TF_ACKNOW) ||
            (sbavail(&so->so_snd) > (tp->snd_max - tp->snd_una))) {
                rack->r_wanted_output = 1;
        }
        return (0);
}

/*
 * Here nothing is really faster, its just that we
 * have broken out the fast-data path also just like
 * the fast-ack.
 */
static int
rack_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t nsegs;
        int32_t newsize = 0;    /* automatic sockbuf scaling */
        struct tcp_rack *rack;
#ifdef NETFLIX_SB_LIMITS
        u_int mcnt, appended;
#endif

        /*
         * If last ACK falls within this segment's sequence numbers, record
         * the timestamp. NOTE that the test is modified according to the
         * latest proposal of the tcplw@cray.com list (Braden 1993/04/26).
         */
        if (__predict_false(th->th_seq != tp->rcv_nxt)) {
                return (0);
        }
        if (tiwin && tiwin != tp->snd_wnd) {
                return (0);
        }
        if (__predict_false((tp->t_flags & (TF_NEEDSYN | TF_NEEDFIN)))) {
                return (0);
        }
        if (__predict_false((to->to_flags & TOF_TS) &&
            (TSTMP_LT(to->to_tsval, tp->ts_recent)))) {
                return (0);
        }
        if (__predict_false((th->th_ack != tp->snd_una))) {
                return (0);
        }
        if (__predict_false(tlen > sbspace(&so->so_rcv))) {
                return (0);
        }
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        /*
         * This is a pure, in-sequence data packet with nothing on the
         * reassembly queue and we have enough buffer space to take it.
         */
        nsegs = max(1, m->m_pkthdr.lro_nsegs);

#ifdef NETFLIX_SB_LIMITS
        if (so->so_rcv.sb_shlim) {
                mcnt = m_memcnt(m);
                appended = 0;
                if (counter_fo_get(so->so_rcv.sb_shlim, mcnt,
                    CFO_NOSLEEP, NULL) == false) {
                        counter_u64_add(tcp_sb_shlim_fails, 1);
                        m_freem(m);
                        return (1);
                }
        }
#endif
        /* Clean receiver SACK report if present */
        if (tp->rcv_numsacks)
                tcp_clean_sackreport(tp);
        KMOD_TCPSTAT_INC(tcps_preddat);
        tp->rcv_nxt += tlen;
        if (tlen &&
            ((tp->t_flags2 & TF2_FBYTES_COMPLETE) == 0) &&
            (tp->t_fbyte_in == 0)) {
                tp->t_fbyte_in = ticks;
                if (tp->t_fbyte_in == 0)
                        tp->t_fbyte_in = 1;
                if (tp->t_fbyte_out && tp->t_fbyte_in)
                        tp->t_flags2 |= TF2_FBYTES_COMPLETE;
        }
        /*
         * Pull snd_wl1 up to prevent seq wrap relative to th_seq.
         */
        tp->snd_wl1 = th->th_seq;
        /*
         * Pull rcv_up up to prevent seq wrap relative to rcv_nxt.
         */
        tp->rcv_up = tp->rcv_nxt;
        KMOD_TCPSTAT_ADD(tcps_rcvpack, nsegs);
        KMOD_TCPSTAT_ADD(tcps_rcvbyte, tlen);
        newsize = tcp_autorcvbuf(m, th, so, tp, tlen);

        /* Add data to socket buffer. */
        SOCK_RECVBUF_LOCK(so);
        if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                m_freem(m);
        } else {
                /*
                 * Set new socket buffer size. Give up when limit is
                 * reached.
                 */
                if (newsize)
                        if (!sbreserve_locked(so, SO_RCV, newsize, NULL))
                                so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
                m_adj(m, drop_hdrlen);  /* delayed header drop */
#ifdef NETFLIX_SB_LIMITS
                appended =
#endif
                        sbappendstream_locked(&so->so_rcv, m, 0);
                ctf_calc_rwin(so, tp);
        }
        rack_log_wakeup(tp,rack, &so->so_rcv, tlen, 1);
        /* NB: sorwakeup_locked() does an implicit unlock. */
        sorwakeup_locked(so);
#ifdef NETFLIX_SB_LIMITS
        if (so->so_rcv.sb_shlim && mcnt != appended)
                counter_fo_release(so->so_rcv.sb_shlim, mcnt - appended);
#endif
        rack_handle_delayed_ack(tp, rack, tlen, 0);
        if (tp->snd_una == tp->snd_max)
                sack_filter_clear(&rack->r_ctl.rack_sf, tp->snd_una);
        return (1);
}

/*
 * This subfunction is used to try to highly optimize the
 * fast path. We again allow window updates that are
 * in sequence to remain in the fast-path. We also add
 * in the __predict's to attempt to help the compiler.
 * Note that if we return a 0, then we can *not* process
 * it and the caller should push the packet into the
 * slow-path.
 */
static int
rack_fastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t nxt_pkt, uint32_t cts)
{
        int32_t acked;
        int32_t nsegs;
        int32_t under_pacing = 0;
        struct tcp_rack *rack;

        if (__predict_false(SEQ_LEQ(th->th_ack, tp->snd_una))) {
                /* Old ack, behind (or duplicate to) the last one rcv'd */
                return (0);
        }
        if (__predict_false(SEQ_GT(th->th_ack, tp->snd_max))) {
                /* Above what we have sent? */
                return (0);
        }
        if (__predict_false(tiwin == 0)) {
                /* zero window */
                return (0);
        }
        if (__predict_false(tp->t_flags & (TF_NEEDSYN | TF_NEEDFIN))) {
                /* We need a SYN or a FIN, unlikely.. */
                return (0);
        }
        if ((to->to_flags & TOF_TS) && __predict_false(TSTMP_LT(to->to_tsval, tp->ts_recent))) {
                /* Timestamp is behind .. old ack with seq wrap? */
                return (0);
        }
        if (__predict_false(IN_RECOVERY(tp->t_flags))) {
                /* Still recovering */
                return (0);
        }
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->r_ctl.rc_sacked) {
                /* We have sack holes on our scoreboard */
                return (0);
        }
        /* Ok if we reach here, we can process a fast-ack */
        if (rack->gp_ready &&
            (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT)) {
                under_pacing = 1;
        }
        nsegs = max(1, m->m_pkthdr.lro_nsegs);
        rack_log_ack(tp, to, th, 0, 0, NULL, NULL);
        /* Did the window get updated? */
        if (tiwin != tp->snd_wnd) {
                tp->snd_wnd = tiwin;
                rack_validate_fo_sendwin_up(tp, rack);
                tp->snd_wl1 = th->th_seq;
                if (tp->snd_wnd > tp->max_sndwnd)
                        tp->max_sndwnd = tp->snd_wnd;
        }
        /* Do we exit persists? */
        if ((rack->rc_in_persist != 0) &&
            (tp->snd_wnd >= min((rack->r_ctl.rc_high_rwnd/2),
                               rack->r_ctl.rc_pace_min_segs))) {
                rack_exit_persist(tp, rack, cts);
        }
        /* Do we enter persists? */
        if ((rack->rc_in_persist == 0) &&
            (tp->snd_wnd < min((rack->r_ctl.rc_high_rwnd/2), rack->r_ctl.rc_pace_min_segs)) &&
            TCPS_HAVEESTABLISHED(tp->t_state) &&
            ((tp->snd_max == tp->snd_una) || rack->rc_has_collapsed) &&
            sbavail(&tptosocket(tp)->so_snd) &&
            (sbavail(&tptosocket(tp)->so_snd) > tp->snd_wnd)) {
                /*
                 * Here the rwnd is less than
                 * the pacing size, we are established,
                 * nothing is outstanding, and there is
                 * data to send. Enter persists.
                 */
                rack_enter_persist(tp, rack, rack->r_ctl.rc_rcvtime, th->th_ack);
        }
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * the timestamp. NOTE that the test is modified according to the
         * latest proposal of the tcplw@cray.com list (Braden 1993/04/26).
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * This is a pure ack for outstanding data.
         */
        KMOD_TCPSTAT_INC(tcps_predack);

        /*
         * "bad retransmit" recovery.
         */
        if ((tp->t_flags & TF_PREVVALID) &&
            ((tp->t_flags & TF_RCVD_TSTMP) == 0)) {
                tp->t_flags &= ~TF_PREVVALID;
                if (tp->t_rxtshift == 1 &&
                    (int)(ticks - tp->t_badrxtwin) < 0)
                        rack_cong_signal(tp, CC_RTO_ERR, th->th_ack, __LINE__);
        }
        /*
         * Recalculate the transmit timer / rtt.
         *
         * Some boxes send broken timestamp replies during the SYN+ACK
         * phase, ignore timestamps of 0 or we could calculate a huge RTT
         * and blow up the retransmit timer.
         */
        acked = BYTES_THIS_ACK(tp, th);

#ifdef TCP_HHOOK
        /* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */
        hhook_run_tcp_est_in(tp, th, to);
#endif
        KMOD_TCPSTAT_ADD(tcps_rcvackpack, nsegs);
        KMOD_TCPSTAT_ADD(tcps_rcvackbyte, acked);
        if (acked) {
                struct mbuf *mfree;

                rack_ack_received(tp, rack, th->th_ack, nsegs, CC_ACK, 0);
                SOCK_SENDBUF_LOCK(so);
                mfree = sbcut_locked(&so->so_snd, acked);
                tp->snd_una = th->th_ack;
                /* Note we want to hold the sb lock through the sendmap adjust */
                rack_adjust_sendmap_head(rack, &so->so_snd);
                /* Wake up the socket if we have room to write more */
                rack_log_wakeup(tp,rack, &so->so_snd, acked, 2);
                sowwakeup_locked(so);
                m_freem(mfree);
                tp->t_rxtshift = 0;
                RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                              rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
                rack->rc_tlp_in_progress = 0;
                rack->r_ctl.rc_tlp_cnt_out = 0;
                /*
                 * If it is the RXT timer we want to
                 * stop it, so we can restart a TLP.
                 */
                if (rack->r_ctl.rc_hpts_flags & PACE_TMR_RXT)
                        rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);

#ifdef TCP_REQUEST_TRK
                rack_req_check_for_comp(rack, th->th_ack);
#endif
        }
        /*
         * Let the congestion control algorithm update congestion control
         * related information. This typically means increasing the
         * congestion window.
         */
        if (tp->snd_wnd < ctf_outstanding(tp)) {
                /* The peer collapsed the window */
                rack_collapsed_window(rack, ctf_outstanding(tp), th->th_ack, __LINE__);
        } else if (rack->rc_has_collapsed)
                rack_un_collapse_window(rack, __LINE__);
        if ((rack->r_collapse_point_valid) &&
            (SEQ_GT(tp->snd_una, rack->r_ctl.high_collapse_point)))
                rack->r_collapse_point_valid = 0;
        /*
         * Pull snd_wl2 up to prevent seq wrap relative to th_ack.
         */
        tp->snd_wl2 = th->th_ack;
        tp->t_dupacks = 0;
        m_freem(m);
        /* ND6_HINT(tp);         *//* Some progress has been made. */

        /*
         * If all outstanding data are acked, stop retransmit timer,
         * otherwise restart timer using current (possibly backed-off)
         * value. If process is waiting for space, wakeup/selwakeup/signal.
         * If data are ready to send, let tcp_output decide between more
         * output or persist.
         */
        if (under_pacing &&
            (rack->use_fixed_rate == 0) &&
            (rack->in_probe_rtt == 0) &&
            rack->rc_gp_dyn_mul &&
            rack->rc_always_pace) {
                /* Check if we are dragging bottom */
                rack_check_bottom_drag(tp, rack, so);
        }
        if (tp->snd_una == tp->snd_max) {
                tp->t_flags &= ~TF_PREVVALID;
                rack->r_ctl.retran_during_recovery = 0;
                rack->rc_suspicious = 0;
                rack->r_ctl.dsack_byte_cnt = 0;
                rack->r_ctl.rc_went_idle_time = tcp_get_usecs(NULL);
                if (rack->r_ctl.rc_went_idle_time == 0)
                        rack->r_ctl.rc_went_idle_time = 1;
                rack_log_progress_event(rack, tp, 0, PROGRESS_CLEAR, __LINE__);
                if (sbavail(&tptosocket(tp)->so_snd) == 0)
                        tp->t_acktime = 0;
                rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
        }
        if (acked && rack->r_fast_output)
                rack_gain_for_fastoutput(rack, tp, so, (uint32_t)acked);
        if (sbavail(&so->so_snd)) {
                rack->r_wanted_output = 1;
        }
        return (1);
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_syn_sent(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen = tlen;
        int32_t todrop;
        int32_t ourfinisacked = 0;
        struct tcp_rack *rack;

        INP_WLOCK_ASSERT(tptoinpcb(tp));

        ctf_calc_rwin(so, tp);
        /*
         * If the state is SYN_SENT: if seg contains an ACK, but not for our
         * SYN, drop the input. if seg contains a RST, then drop the
         * connection. if seg does not contain SYN, then drop it. Otherwise
         * this is an acceptable SYN segment initialize tp->rcv_nxt and
         * tp->irs if seg contains ack then advance tp->snd_una if seg
         * contains an ECE and ECN support is enabled, the stream is ECN
         * capable. if SYN has been acked change to ESTABLISHED else
         * SYN_RCVD state arrange for segment to be acked (eventually)
         * continue processing rest of data/controls.
         */
        if ((thflags & TH_ACK) &&
            (SEQ_LEQ(th->th_ack, tp->iss) ||
            SEQ_GT(th->th_ack, tp->snd_max))) {
                tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
                ctf_do_dropwithreset(m, tp, th, tlen);
                return (1);
        }
        if ((thflags & (TH_ACK | TH_RST)) == (TH_ACK | TH_RST)) {
                TCP_PROBE5(connect__refused, NULL, tp,
                    mtod(m, const char *), tp, th);
                tp = tcp_drop(tp, ECONNREFUSED);
                ctf_do_drop(m, tp);
                return (1);
        }
        if (thflags & TH_RST) {
                ctf_do_drop(m, tp);
                return (1);
        }
        if (!(thflags & TH_SYN)) {
                ctf_do_drop(m, tp);
                return (1);
        }
        tp->irs = th->th_seq;
        tcp_rcvseqinit(tp);
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (thflags & TH_ACK) {
                int tfo_partial = 0;

                KMOD_TCPSTAT_INC(tcps_connects);
                soisconnected(so);
#ifdef MAC
                mac_socketpeer_set_from_mbuf(m, so);
#endif
                /* Do window scaling on this connection? */
                if ((tp->t_flags & (TF_RCVD_SCALE | TF_REQ_SCALE)) ==
                    (TF_RCVD_SCALE | TF_REQ_SCALE)) {
                        tp->rcv_scale = tp->request_r_scale;
                }
                tp->rcv_adv += min(tp->rcv_wnd,
                    TCP_MAXWIN << tp->rcv_scale);
                /*
                 * If not all the data that was sent in the TFO SYN
                 * has been acked, resend the remainder right away.
                 */
                if ((tp->t_flags & TF_FASTOPEN) &&
                    (tp->snd_una != tp->snd_max)) {
                        /* Was it a partial ack? */
                        if (SEQ_LT(th->th_ack, tp->snd_max))
                                tfo_partial = 1;
                }
                /*
                 * If there's data, delay ACK; if there's also a FIN ACKNOW
                 * will be turned on later.
                 */
                if (DELAY_ACK(tp, tlen) && tlen != 0 && !tfo_partial) {
                        rack_timer_cancel(tp, rack,
                                          rack->r_ctl.rc_rcvtime, __LINE__);
                        tp->t_flags |= TF_DELACK;
                } else {
                        rack->r_wanted_output = 1;
                        tp->t_flags |= TF_ACKNOW;
                }

                tcp_ecn_input_syn_sent(tp, thflags, iptos);

                if (SEQ_GT(th->th_ack, tp->snd_una)) {
                        /*
                         * We advance snd_una for the
                         * fast open case. If th_ack is
                         * acknowledging data beyond
                         * snd_una we can't just call
                         * ack-processing since the
                         * data stream in our send-map
                         * will start at snd_una + 1 (one
                         * beyond the SYN). If its just
                         * equal we don't need to do that
                         * and there is no send_map.
                         */
                        tp->snd_una++;
                        if (tfo_partial && (SEQ_GT(tp->snd_max, tp->snd_una))) {
                                /*
                                 * We sent a SYN with data, and thus have a
                                 * sendmap entry with a SYN set. Lets find it
                                 * and take off the send bit and the byte and
                                 * set it up to be what we send (send it next).
                                 */
                                struct rack_sendmap *rsm;

                                rsm = tqhash_min(rack->r_ctl.tqh);
                                if (rsm) {
                                        if (rsm->r_flags & RACK_HAS_SYN) {
                                                rsm->r_flags &= ~RACK_HAS_SYN;
                                                rsm->r_start++;
                                        }
                                        rack->r_ctl.rc_resend = rsm;
                                }
                        }
                }
                /*
                 * Received <SYN,ACK> in SYN_SENT[*] state. Transitions:
                 * SYN_SENT  --> ESTABLISHED SYN_SENT* --> FIN_WAIT_1
                 */
                tp->t_starttime = ticks;
                if (tp->t_flags & TF_NEEDFIN) {
                        tcp_state_change(tp, TCPS_FIN_WAIT_1);
                        tp->t_flags &= ~TF_NEEDFIN;
                        thflags &= ~TH_SYN;
                } else {
                        tcp_state_change(tp, TCPS_ESTABLISHED);
                        TCP_PROBE5(connect__established, NULL, tp,
                            mtod(m, const char *), tp, th);
                        rack_cc_conn_init(tp);
                }
        } else {
                /*
                 * Received initial SYN in SYN-SENT[*] state => simultaneous
                 * open.  If segment contains CC option and there is a
                 * cached CC, apply TAO test. If it succeeds, connection is *
                 * half-synchronized. Otherwise, do 3-way handshake:
                 * SYN-SENT -> SYN-RECEIVED SYN-SENT* -> SYN-RECEIVED* If
                 * there was no CC option, clear cached CC value.
                 */
                tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN | TF_SONOTCONN);
                tcp_state_change(tp, TCPS_SYN_RECEIVED);
        }
        /*
         * Advance th->th_seq to correspond to first data byte. If data,
         * trim to stay within window, dropping FIN if necessary.
         */
        th->th_seq++;
        if (tlen > tp->rcv_wnd) {
                todrop = tlen - tp->rcv_wnd;
                m_adj(m, -todrop);
                tlen = tp->rcv_wnd;
                thflags &= ~TH_FIN;
                KMOD_TCPSTAT_INC(tcps_rcvpackafterwin);
                KMOD_TCPSTAT_ADD(tcps_rcvbyteafterwin, todrop);
        }
        tp->snd_wl1 = th->th_seq - 1;
        tp->rcv_up = th->th_seq;
        /*
         * Client side of transaction: already sent SYN and data. If the
         * remote host used T/TCP to validate the SYN, our data will be
         * ACK'd; if so, enter normal data segment processing in the middle
         * of step 5, ack processing. Otherwise, goto step 6.
         */
        if (thflags & TH_ACK) {
                /* For syn-sent we need to possibly update the rtt */
                if ((to->to_flags & TOF_TS) != 0 && to->to_tsecr) {
                        uint32_t t, mcts;

                        mcts = tcp_ts_getticks();
                        t = (mcts - to->to_tsecr) * HPTS_USEC_IN_MSEC;
                        if (!tp->t_rttlow || tp->t_rttlow > t)
                                tp->t_rttlow = t;
                        rack_log_rtt_sample_calc(rack, t, (to->to_tsecr * 1000), (mcts * 1000), 4);
                        tcp_rack_xmit_timer(rack, t + 1, 1, t, 0, NULL, 2);
                        tcp_rack_xmit_timer_commit(rack, tp);
                }
                if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val, orig_tlen))
                        return (ret_val);
                /* We may have changed to FIN_WAIT_1 above */
                if (tp->t_state == TCPS_FIN_WAIT_1) {
                        /*
                         * In FIN_WAIT_1 STATE in addition to the processing
                         * for the ESTABLISHED state if our FIN is now
                         * acknowledged then enter FIN_WAIT_2.
                         */
                        if (ourfinisacked) {
                                /*
                                 * If we can't receive any more data, then
                                 * closing user can proceed. Starting the
                                 * timer is contrary to the specification,
                                 * but if we don't get a FIN we'll hang
                                 * forever.
                                 *
                                 * XXXjl: we should release the tp also, and
                                 * use a compressed state.
                                 */
                                if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                                        soisdisconnected(so);
                                        tcp_timer_activate(tp, TT_2MSL,
                                            (tcp_fast_finwait2_recycle ?
                                            tcp_finwait2_timeout :
                                            TP_MAXIDLE(tp)));
                                }
                                tcp_state_change(tp, TCPS_FIN_WAIT_2);
                        }
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
           tiwin, thflags, nxt_pkt));
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        struct tcp_rack *rack;
        int32_t orig_tlen = tlen;
        int32_t ret_val = 0;
        int32_t ourfinisacked = 0;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        ctf_calc_rwin(so, tp);
        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));
        if ((thflags & TH_ACK) &&
            (SEQ_LEQ(th->th_ack, tp->snd_una) ||
            SEQ_GT(th->th_ack, tp->snd_max))) {
                tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
                ctf_do_dropwithreset(m, tp, th, tlen);
                return (1);
        }
        if (tp->t_flags & TF_FASTOPEN) {
                /*
                 * When a TFO connection is in SYN_RECEIVED, the
                 * only valid packets are the initial SYN, a
                 * retransmit/copy of the initial SYN (possibly with
                 * a subset of the original data), a valid ACK, a
                 * FIN, or a RST.
                 */
                if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
                        tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
                        ctf_do_dropwithreset(m, tp, th, tlen);
                        return (1);
                } else if (thflags & TH_SYN) {
                        /* non-initial SYN is ignored */
                        if ((rack->r_ctl.rc_hpts_flags & PACE_TMR_RXT) ||
                            (rack->r_ctl.rc_hpts_flags & PACE_TMR_TLP) ||
                            (rack->r_ctl.rc_hpts_flags & PACE_TMR_RACK)) {
                                ctf_do_drop(m, NULL);
                                return (0);
                        }
                } else if (!(thflags & (TH_ACK | TH_FIN | TH_RST))) {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }

        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        /*
         * In the SYN-RECEIVED state, validate that the packet belongs to
         * this connection before trimming the data to fit the receive
         * window.  Check the sequence number versus IRS since we know the
         * sequence numbers haven't wrapped.  This is a partial fix for the
         * "LAND" DoS attack.
         */
        if (SEQ_LT(th->th_seq, tp->irs)) {
                tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
                ctf_do_dropwithreset(m, tp, th, tlen);
                return (1);
        }
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        tp->snd_wnd = tiwin;
        rack_validate_fo_sendwin_up(tp, rack);
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_FASTOPEN) {
                        rack_cc_conn_init(tp);
                }
                return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                    tiwin, thflags, nxt_pkt));
        }
        KMOD_TCPSTAT_INC(tcps_connects);
        if (tp->t_flags & TF_SONOTCONN) {
                tp->t_flags &= ~TF_SONOTCONN;
                soisconnected(so);
        }
        /* Do window scaling? */
        if ((tp->t_flags & (TF_RCVD_SCALE | TF_REQ_SCALE)) ==
            (TF_RCVD_SCALE | TF_REQ_SCALE)) {
                tp->rcv_scale = tp->request_r_scale;
        }
        /*
         * Make transitions: SYN-RECEIVED  -> ESTABLISHED SYN-RECEIVED* ->
         * FIN-WAIT-1
         */
        tp->t_starttime = ticks;
        if ((tp->t_flags & TF_FASTOPEN) && tp->t_tfo_pending) {
                tcp_fastopen_decrement_counter(tp->t_tfo_pending);
                tp->t_tfo_pending = NULL;
        }
        if (tp->t_flags & TF_NEEDFIN) {
                tcp_state_change(tp, TCPS_FIN_WAIT_1);
                tp->t_flags &= ~TF_NEEDFIN;
        } else {
                tcp_state_change(tp, TCPS_ESTABLISHED);
                TCP_PROBE5(accept__established, NULL, tp,
                    mtod(m, const char *), tp, th);
                /*
                 * TFO connections call cc_conn_init() during SYN
                 * processing.  Calling it again here for such connections
                 * is not harmless as it would undo the snd_cwnd reduction
                 * that occurs when a TFO SYN|ACK is retransmitted.
                 */
                if (!(tp->t_flags & TF_FASTOPEN))
                        rack_cc_conn_init(tp);
        }
        /*
         * Account for the ACK of our SYN prior to
         * regular ACK processing below, except for
         * simultaneous SYN, which is handled later.
         */
        if (SEQ_GT(th->th_ack, tp->snd_una) && !(tp->t_flags & TF_NEEDSYN))
                tp->snd_una++;
        /*
         * If segment contains data or ACK, will call tcp_reass() later; if
         * not, do so now to pass queued data to user.
         */
        if (tlen == 0 && (thflags & TH_FIN) == 0) {
                (void) tcp_reass(tp, (struct tcphdr *)0, NULL, 0,
                    (struct mbuf *)0);
                if (tp->t_flags & TF_WAKESOR) {
                        tp->t_flags &= ~TF_WAKESOR;
                        /* NB: sorwakeup_locked() does an implicit unlock. */
                        sorwakeup_locked(so);
                }
        }
        tp->snd_wl1 = th->th_seq - 1;
        /* For syn-recv we need to possibly update the rtt */
        if ((to->to_flags & TOF_TS) != 0 && to->to_tsecr) {
                uint32_t t, mcts;

                mcts = tcp_ts_getticks();
                t = (mcts - to->to_tsecr) * HPTS_USEC_IN_MSEC;
                if (!tp->t_rttlow || tp->t_rttlow > t)
                        tp->t_rttlow = t;
                rack_log_rtt_sample_calc(rack, t, (to->to_tsecr * 1000), (mcts * 1000), 5);
                tcp_rack_xmit_timer(rack, t + 1, 1, t, 0, NULL, 2);
                tcp_rack_xmit_timer_commit(rack, tp);
        }
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (tp->t_state == TCPS_FIN_WAIT_1) {
                /* We could have went to FIN_WAIT_1 (or EST) above */
                /*
                 * In FIN_WAIT_1 STATE in addition to the processing for the
                 * ESTABLISHED state if our FIN is now acknowledged then
                 * enter FIN_WAIT_2.
                 */
                if (ourfinisacked) {
                        /*
                         * If we can't receive any more data, then closing
                         * user can proceed. Starting the timer is contrary
                         * to the specification, but if we don't get a FIN
                         * we'll hang forever.
                         *
                         * XXXjl: we should release the tp also, and use a
                         * compressed state.
                         */
                        if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                                soisdisconnected(so);
                                tcp_timer_activate(tp, TT_2MSL,
                                    (tcp_fast_finwait2_recycle ?
                                    tcp_finwait2_timeout :
                                    TP_MAXIDLE(tp)));
                        }
                        tcp_state_change(tp, TCPS_FIN_WAIT_2);
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_established(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen = tlen;
        struct tcp_rack *rack;

        /*
         * Header prediction: check for the two common cases of a
         * uni-directional data xfer.  If the packet has no control flags,
         * is in-sequence, the window didn't change and we're not
         * retransmitting, it's a candidate.  If the length is zero and the
         * ack moved forward, we're the sender side of the xfer.  Just free
         * the data acked & wake any higher level process that was blocked
         * waiting for space.  If the length is non-zero and the ack didn't
         * move, we're the receiver side.  If we're getting packets in-order
         * (the reassembly queue is empty), add the data toc The socket
         * buffer and note that we need a delayed ack. Make sure that the
         * hidden state-flags are also off. Since we check for
         * TCPS_ESTABLISHED first, it can only be TH_NEEDSYN.
         */
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (__predict_true(((to->to_flags & TOF_SACK) == 0)) &&
            __predict_true((thflags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) == TH_ACK) &&
            __predict_true(SEGQ_EMPTY(tp)) &&
            __predict_true(th->th_seq == tp->rcv_nxt)) {
                if (tlen == 0) {
                        if (rack_fastack(m, th, so, tp, to, drop_hdrlen, tlen,
                            tiwin, nxt_pkt, rack->r_ctl.rc_rcvtime)) {
                                return (0);
                        }
                } else {
                        if (rack_do_fastnewdata(m, th, so, tp, to, drop_hdrlen, tlen,
                            tiwin, nxt_pkt, iptos)) {
                                return (0);
                        }
                }
        }
        ctf_calc_rwin(so, tp);

        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));

        /*
         * RFC5961 Section 4.2 Send challenge ACK for any SYN in
         * synchronized state.
         */
        if (thflags & TH_SYN) {
                ctf_challenge_ack(m, th, tp, iptos, &ret_val);
                return (ret_val);
        }
        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_NEEDSYN) {
                        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                            tiwin, thflags, nxt_pkt));

                } else if (tp->t_flags & TF_ACKNOW) {
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, &ret_val);
                        ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output = 1;
                        return (ret_val);
                } else {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }
        /*
         * Ack processing.
         */
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, NULL, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (sbavail(&so->so_snd)) {
                if (ctf_progress_timeout_check(tp, true)) {
                        rack_log_progress_event(rack, tp, tick, PROGRESS_DROP, __LINE__);
                        ctf_do_dropwithreset_conn(m, tp, th, tlen);
                        return (1);
                }
        }
        /* State changes only happen in rack_process_data() */
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_close_wait(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen = tlen;

        ctf_calc_rwin(so, tp);
        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));
        /*
         * RFC5961 Section 4.2 Send challenge ACK for any SYN in
         * synchronized state.
         */
        if (thflags & TH_SYN) {
                ctf_challenge_ack(m, th, tp, iptos, &ret_val);
                return (ret_val);
        }
        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_NEEDSYN) {
                        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                            tiwin, thflags, nxt_pkt));

                } else if (tp->t_flags & TF_ACKNOW) {
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, &ret_val);
                        ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output = 1;
                        return (ret_val);
                } else {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }
        /*
         * Ack processing.
         */
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, NULL, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (sbavail(&so->so_snd)) {
                if (ctf_progress_timeout_check(tp, true)) {
                        rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
                                                tp, tick, PROGRESS_DROP, __LINE__);
                        ctf_do_dropwithreset_conn(m, tp, th, tlen);
                        return (1);
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

static int
rack_check_data_after_close(struct mbuf *m,
    struct tcpcb *tp, int32_t *tlen, struct tcphdr *th, struct socket *so)
{
        struct tcp_rack *rack;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->rc_allow_data_af_clo == 0) {
        close_now:
                tcp_log_end_status(tp, TCP_EI_STATUS_DATA_A_CLOSE);
                /* tcp_close will kill the inp pre-log the Reset */
                tcp_log_end_status(tp, TCP_EI_STATUS_SERVER_RST);
                tp = tcp_close(tp);
                KMOD_TCPSTAT_INC(tcps_rcvafterclose);
                ctf_do_dropwithreset(m, tp, th, *tlen);
                return (1);
        }
        if (sbavail(&so->so_snd) == 0)
                goto close_now;
        /* Ok we allow data that is ignored and a followup reset */
        tcp_log_end_status(tp, TCP_EI_STATUS_DATA_A_CLOSE);
        tp->rcv_nxt = th->th_seq + *tlen;
        tp->t_flags2 |= TF2_DROP_AF_DATA;
        rack->r_wanted_output = 1;
        *tlen = 0;
        return (0);
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_fin_wait_1(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen = tlen;
        int32_t ourfinisacked = 0;

        ctf_calc_rwin(so, tp);

        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));
        /*
         * RFC5961 Section 4.2 Send challenge ACK for any SYN in
         * synchronized state.
         */
        if (thflags & TH_SYN) {
                ctf_challenge_ack(m, th, tp, iptos, &ret_val);
                return (ret_val);
        }
        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If new data are received on a connection after the user processes
         * are gone, then RST the other end.
         */
        if ((tp->t_flags & TF_CLOSED) && tlen &&
            rack_check_data_after_close(m, tp, &tlen, th, so))
                return (1);
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_NEEDSYN) {
                        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                            tiwin, thflags, nxt_pkt));
                } else if (tp->t_flags & TF_ACKNOW) {
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, &ret_val);
                        ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output = 1;
                        return (ret_val);
                } else {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }
        /*
         * Ack processing.
         */
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (ourfinisacked) {
                /*
                 * If we can't receive any more data, then closing user can
                 * proceed. Starting the timer is contrary to the
                 * specification, but if we don't get a FIN we'll hang
                 * forever.
                 *
                 * XXXjl: we should release the tp also, and use a
                 * compressed state.
                 */
                if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                        soisdisconnected(so);
                        tcp_timer_activate(tp, TT_2MSL,
                            (tcp_fast_finwait2_recycle ?
                            tcp_finwait2_timeout :
                            TP_MAXIDLE(tp)));
                }
                tcp_state_change(tp, TCPS_FIN_WAIT_2);
        }
        if (sbavail(&so->so_snd)) {
                if (ctf_progress_timeout_check(tp, true)) {
                        rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
                                                tp, tick, PROGRESS_DROP, __LINE__);
                        ctf_do_dropwithreset_conn(m, tp, th, tlen);
                        return (1);
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_closing(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen = tlen;
        int32_t ourfinisacked = 0;

        ctf_calc_rwin(so, tp);

        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));
        /*
         * RFC5961 Section 4.2 Send challenge ACK for any SYN in
         * synchronized state.
         */
        if (thflags & TH_SYN) {
                ctf_challenge_ack(m, th, tp, iptos, &ret_val);
                return (ret_val);
        }
        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_NEEDSYN) {
                        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                            tiwin, thflags, nxt_pkt));
                } else if (tp->t_flags & TF_ACKNOW) {
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, &ret_val);
                        ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output = 1;
                        return (ret_val);
                } else {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }
        /*
         * Ack processing.
         */
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (ourfinisacked) {
                tcp_twstart(tp);
                m_freem(m);
                return (1);
        }
        if (sbavail(&so->so_snd)) {
                if (ctf_progress_timeout_check(tp, true)) {
                        rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
                                                tp, tick, PROGRESS_DROP, __LINE__);
                        ctf_do_dropwithreset_conn(m, tp, th, tlen);
                        return (1);
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_lastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen;
        int32_t ourfinisacked = 0;

        ctf_calc_rwin(so, tp);

        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));
        /*
         * RFC5961 Section 4.2 Send challenge ACK for any SYN in
         * synchronized state.
         */
        if (thflags & TH_SYN) {
                ctf_challenge_ack(m, th, tp, iptos, &ret_val);
                return (ret_val);
        }
        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        orig_tlen = tlen;
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_NEEDSYN) {
                        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                            tiwin, thflags, nxt_pkt));
                } else if (tp->t_flags & TF_ACKNOW) {
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, &ret_val);
                        ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output = 1;
                        return (ret_val);
                } else {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }
        /*
         * case TCPS_LAST_ACK: Ack processing.
         */
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (ourfinisacked) {
                tp = tcp_close(tp);
                ctf_do_drop(m, tp);
                return (1);
        }
        if (sbavail(&so->so_snd)) {
                if (ctf_progress_timeout_check(tp, true)) {
                        rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
                                                tp, tick, PROGRESS_DROP, __LINE__);
                        ctf_do_dropwithreset_conn(m, tp, th, tlen);
                        return (1);
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

/*
 * Return value of 1, the TCB is unlocked and most
 * likely gone, return value of 0, the TCP is still
 * locked.
 */
static int
rack_do_fin_wait_2(struct mbuf *m, struct tcphdr *th, struct socket *so,
    struct tcpcb *tp, struct tcpopt *to, int32_t drop_hdrlen, int32_t tlen,
    uint32_t tiwin, int32_t thflags, int32_t nxt_pkt, uint8_t iptos)
{
        int32_t ret_val = 0;
        int32_t orig_tlen = tlen;
        int32_t ourfinisacked = 0;

        ctf_calc_rwin(so, tp);

        /* Reset receive buffer auto scaling when not in bulk receive mode. */
        if ((thflags & TH_RST) ||
            (tp->t_fin_is_rst && (thflags & TH_FIN)))
                return (ctf_process_rst(m, th, so, tp));
        /*
         * RFC5961 Section 4.2 Send challenge ACK for any SYN in
         * synchronized state.
         */
        if (thflags & TH_SYN) {
                ctf_challenge_ack(m, th, tp, iptos, &ret_val);
                return (ret_val);
        }
        /*
         * RFC 1323 PAWS: If we have a timestamp reply on this segment and
         * it's less than ts_recent, drop it.
         */
        if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent &&
            TSTMP_LT(to->to_tsval, tp->ts_recent)) {
                if (ctf_ts_check(m, th, tp, tlen, thflags, &ret_val))
                        return (ret_val);
        }
        if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
                return (ret_val);
        }
        /*
         * If new data are received on a connection after the user processes
         * are gone, then RST the other end.
         */
        if ((tp->t_flags & TF_CLOSED) && tlen &&
            rack_check_data_after_close(m, tp, &tlen, th, so))
                return (1);
        /*
         * If last ACK falls within this segment's sequence numbers, record
         * its timestamp. NOTE: 1) That the test incorporates suggestions
         * from the latest proposal of the tcplw@cray.com list (Braden
         * 1993/04/26). 2) That updating only on newer timestamps interferes
         * with our earlier PAWS tests, so this check should be solely
         * predicated on the sequence space of this segment. 3) That we
         * modify the segment boundary check to be Last.ACK.Sent <= SEG.SEQ
         * + SEG.Len  instead of RFC1323's Last.ACK.Sent < SEG.SEQ +
         * SEG.Len, This modified check allows us to overcome RFC1323's
         * limitations as described in Stevens TCP/IP Illustrated Vol. 2
         * p.869. In such cases, we can still calculate the RTT correctly
         * when RCV.NXT == Last.ACK.Sent.
         */
        if ((to->to_flags & TOF_TS) != 0 &&
            SEQ_LEQ(th->th_seq, tp->last_ack_sent) &&
            SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
            ((thflags & (TH_SYN | TH_FIN)) != 0))) {
                tp->ts_recent_age = tcp_ts_getticks();
                tp->ts_recent = to->to_tsval;
        }
        /*
         * If the ACK bit is off:  if in SYN-RECEIVED state or SENDSYN flag
         * is on (half-synchronized state), then queue data for later
         * processing; else drop segment and return.
         */
        if ((thflags & TH_ACK) == 0) {
                if (tp->t_flags & TF_NEEDSYN) {
                        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
                            tiwin, thflags, nxt_pkt));
                } else if (tp->t_flags & TF_ACKNOW) {
                        ctf_do_dropafterack(m, tp, th, thflags, tlen, &ret_val);
                        ((struct tcp_rack *)tp->t_fb_ptr)->r_wanted_output = 1;
                        return (ret_val);
                } else {
                        ctf_do_drop(m, NULL);
                        return (0);
                }
        }
        /*
         * Ack processing.
         */
        if (rack_process_ack(m, th, so, tp, to, tiwin, tlen, &ourfinisacked, thflags, &ret_val, orig_tlen)) {
                return (ret_val);
        }
        if (sbavail(&so->so_snd)) {
                if (ctf_progress_timeout_check(tp, true)) {
                        rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
                                                tp, tick, PROGRESS_DROP, __LINE__);
                        ctf_do_dropwithreset_conn(m, tp, th, tlen);
                        return (1);
                }
        }
        return (rack_process_data(m, th, so, tp, drop_hdrlen, tlen,
            tiwin, thflags, nxt_pkt));
}

static void inline
rack_clear_rate_sample(struct tcp_rack *rack)
{
        rack->r_ctl.rack_rs.rs_flags = RACK_RTT_EMPTY;
        rack->r_ctl.rack_rs.rs_rtt_cnt = 0;
        rack->r_ctl.rack_rs.rs_rtt_tot = 0;
}

static void
rack_set_pace_segments(struct tcpcb *tp, struct tcp_rack *rack, uint32_t line, uint64_t *fill_override)
{
        uint64_t bw_est, rate_wanted;
        int chged = 0;
        uint32_t user_max, orig_min, orig_max;

#ifdef TCP_REQUEST_TRK
        if (rack->rc_hybrid_mode &&
            (rack->r_ctl.rc_pace_max_segs != 0) &&
            (rack_hybrid_allow_set_maxseg == 1) &&
            (rack->r_ctl.rc_last_sft != NULL)) {
                rack->r_ctl.rc_last_sft->hybrid_flags &= ~TCP_HYBRID_PACING_SETMSS;
                return;
        }
#endif
        orig_min = rack->r_ctl.rc_pace_min_segs;
        orig_max = rack->r_ctl.rc_pace_max_segs;
        user_max = ctf_fixed_maxseg(tp) * rack->rc_user_set_max_segs;
        if (ctf_fixed_maxseg(tp) != rack->r_ctl.rc_pace_min_segs)
                chged = 1;
        rack->r_ctl.rc_pace_min_segs = ctf_fixed_maxseg(tp);
        if (rack->use_fixed_rate || rack->rc_force_max_seg) {
                if (user_max != rack->r_ctl.rc_pace_max_segs)
                        chged = 1;
        }
        if (rack->rc_force_max_seg) {
                rack->r_ctl.rc_pace_max_segs = user_max;
        } else if (rack->use_fixed_rate) {
                bw_est = rack_get_bw(rack);
                if ((rack->r_ctl.crte == NULL) ||
                    (bw_est != rack->r_ctl.crte->rate)) {
                        rack->r_ctl.rc_pace_max_segs = user_max;
                } else {
                        /* We are pacing right at the hardware rate */
                        uint32_t segsiz, pace_one;

                        if (rack_pace_one_seg ||
                            (rack->r_ctl.rc_user_set_min_segs == 1))
                                pace_one = 1;
                        else
                                pace_one = 0;
                        segsiz = min(ctf_fixed_maxseg(tp),
                                     rack->r_ctl.rc_pace_min_segs);
                        rack->r_ctl.rc_pace_max_segs = tcp_get_pacing_burst_size_w_divisor(
                                tp, bw_est, segsiz, pace_one,
                                rack->r_ctl.crte, NULL, rack->r_ctl.pace_len_divisor);
                }
        } else if (rack->rc_always_pace) {
                if (rack->r_ctl.gp_bw ||
                    rack->r_ctl.init_rate) {
                        /* We have a rate of some sort set */
                        uint32_t  orig;

                        bw_est = rack_get_bw(rack);
                        orig = rack->r_ctl.rc_pace_max_segs;
                        if (fill_override)
                                rate_wanted = *fill_override;
                        else
                                rate_wanted = rack_get_gp_est(rack);
                        if (rate_wanted) {
                                /* We have something */
                                rack->r_ctl.rc_pace_max_segs = rack_get_pacing_len(rack,
                                                                                   rate_wanted,
                                                                                   ctf_fixed_maxseg(rack->rc_tp));
                        } else
                                rack->r_ctl.rc_pace_max_segs = rack->r_ctl.rc_pace_min_segs;
                        if (orig != rack->r_ctl.rc_pace_max_segs)
                                chged = 1;
                } else if ((rack->r_ctl.gp_bw == 0) &&
                           (rack->r_ctl.rc_pace_max_segs == 0)) {
                        /*
                         * If we have nothing limit us to bursting
                         * out IW sized pieces.
                         */
                        chged = 1;
                        rack->r_ctl.rc_pace_max_segs = rc_init_window(rack);
                }
        }
        if (rack->r_ctl.rc_pace_max_segs > PACE_MAX_IP_BYTES) {
                chged = 1;
                rack->r_ctl.rc_pace_max_segs = PACE_MAX_IP_BYTES;
        }
        if (chged)
                rack_log_type_pacing_sizes(tp, rack, orig_min, orig_max, line, 2);
}


static void
rack_init_fsb_block(struct tcpcb *tp, struct tcp_rack *rack, int32_t flags)
{
#ifdef INET6
        struct ip6_hdr *ip6 = NULL;
#endif
#ifdef INET
        struct ip *ip = NULL;
#endif
        struct udphdr *udp = NULL;

        /* Ok lets fill in the fast block, it can only be used with no IP options! */
#ifdef INET6
        if (rack->r_is_v6) {
                rack->r_ctl.fsb.tcp_ip_hdr_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
                ip6 = (struct ip6_hdr *)rack->r_ctl.fsb.tcp_ip_hdr;
                if (tp->t_port) {
                        rack->r_ctl.fsb.tcp_ip_hdr_len += sizeof(struct udphdr);
                        udp = (struct udphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
                        udp->uh_sport = htons(V_tcp_udp_tunneling_port);
                        udp->uh_dport = tp->t_port;
                        rack->r_ctl.fsb.udp = udp;
                        rack->r_ctl.fsb.th = (struct tcphdr *)(udp + 1);
                } else
                {
                        rack->r_ctl.fsb.th = (struct tcphdr *)(ip6 + 1);
                        rack->r_ctl.fsb.udp = NULL;
                }
                tcpip_fillheaders(rack->rc_inp,
                                  tp->t_port,
                                  ip6, rack->r_ctl.fsb.th);
                rack->r_ctl.fsb.hoplimit = in6_selecthlim(rack->rc_inp, NULL);
        } else
#endif                          /* INET6 */
#ifdef INET
        {
                rack->r_ctl.fsb.tcp_ip_hdr_len = sizeof(struct tcpiphdr);
                ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr;
                if (tp->t_port) {
                        rack->r_ctl.fsb.tcp_ip_hdr_len += sizeof(struct udphdr);
                        udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip));
                        udp->uh_sport = htons(V_tcp_udp_tunneling_port);
                        udp->uh_dport = tp->t_port;
                        rack->r_ctl.fsb.udp = udp;
                        rack->r_ctl.fsb.th = (struct tcphdr *)(udp + 1);
                } else
                {
                        rack->r_ctl.fsb.udp = NULL;
                        rack->r_ctl.fsb.th = (struct tcphdr *)(ip + 1);
                }
                tcpip_fillheaders(rack->rc_inp,
                                  tp->t_port,
                                  ip, rack->r_ctl.fsb.th);
                rack->r_ctl.fsb.hoplimit = tptoinpcb(tp)->inp_ip_ttl;
        }
#endif
        rack->r_ctl.fsb.recwin = lmin(lmax(sbspace(&tptosocket(tp)->so_rcv), 0),
            (long)TCP_MAXWIN << tp->rcv_scale);
        rack->r_fsb_inited = 1;
}

static int
rack_init_fsb(struct tcpcb *tp, struct tcp_rack *rack)
{
        /*
         * Allocate the larger of spaces V6 if available else just
         * V4 and include udphdr (overbook)
         */
#ifdef INET6
        rack->r_ctl.fsb.tcp_ip_hdr_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + sizeof(struct udphdr);
#else
        rack->r_ctl.fsb.tcp_ip_hdr_len = sizeof(struct tcpiphdr) + sizeof(struct udphdr);
#endif
        rack->r_ctl.fsb.tcp_ip_hdr = malloc(rack->r_ctl.fsb.tcp_ip_hdr_len,
                                            M_TCPFSB, M_NOWAIT|M_ZERO);
        if (rack->r_ctl.fsb.tcp_ip_hdr == NULL) {
                return (ENOMEM);
        }
        rack->r_fsb_inited = 0;
        return (0);
}

static void
rack_log_hystart_event(struct tcp_rack *rack, uint32_t high_seq, uint8_t mod)
{
        /*
         * Types of logs (mod value)
         * 20 - Initial round setup
         * 21 - Rack declares a new round.
         */
        struct tcpcb *tp;

        tp = rack->rc_tp;
        if (tcp_bblogging_on(tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = rack->r_ctl.current_round;
                log.u_bbr.flex2 = rack->r_ctl.roundends;
                log.u_bbr.flex3 = high_seq;
                log.u_bbr.flex4 = tp->snd_max;
                log.u_bbr.flex8 = mod;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.cur_del_rate = rack->rc_tp->t_sndbytes;
                log.u_bbr.delRate = rack->rc_tp->t_snd_rxt_bytes;
                TCP_LOG_EVENTP(tp, NULL,
                    &tptosocket(tp)->so_rcv,
                    &tptosocket(tp)->so_snd,
                    TCP_HYSTART, 0,
                    0, &log, false, &tv);
        }
}

static void
rack_deferred_init(struct tcpcb *tp, struct tcp_rack *rack)
{
        rack->rack_deferred_inited = 1;
        rack->r_ctl.roundends = tp->snd_max;
        rack->r_ctl.rc_high_rwnd = tp->snd_wnd;
        rack->r_ctl.cwnd_to_use = tp->snd_cwnd;
}

static void
rack_init_retransmit_value(struct tcp_rack *rack, int ctl)
{
        /* Retransmit bit controls.
         *
         * The setting of these values control one of
         * three settings you can have and dictate
         * how rack does retransmissions. Note this
         * is in *any* mode i.e. pacing on or off DGP
         * fixed rate pacing, or just bursting rack.
         *
         * 1 - Use full sized retransmits i.e. limit
         *     the size to whatever the pace_max_segments
         *     size is.
         *
         * 2 - Use pacer min granularity as a guide to
         *     the size combined with the current calculated
         *     goodput b/w measurement. So for example if
         *     the goodput is measured at 20Mbps we would
         *     calculate 8125 (pacer minimum 250usec in
         *     that b/w) and then round it up to the next
         *     MSS i.e. for 1448 mss 6 MSS or 8688 bytes.
         *
         * 0 - The rack default 1 MSS (anything not 0/1/2
         *     fall here too if we are setting via rack_init()).
         *
         */
        if (ctl == 1) {
                rack->full_size_rxt = 1;
                rack->shape_rxt_to_pacing_min  = 0;
        } else if (ctl == 2) {
                rack->full_size_rxt = 0;
                rack->shape_rxt_to_pacing_min  = 1;
        } else {
                rack->full_size_rxt = 0;
                rack->shape_rxt_to_pacing_min  = 0;
        }
}

static void
rack_log_chg_info(struct tcpcb *tp, struct tcp_rack *rack, uint8_t mod,
                  uint32_t flex1,
                  uint32_t flex2,
                  uint32_t flex3)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.flex8 = mod;
                log.u_bbr.flex1 = flex1;
                log.u_bbr.flex2 = flex2;
                log.u_bbr.flex3 = flex3;
                tcp_log_event(tp, NULL, NULL, NULL, TCP_CHG_QUERY, 0,
                               0, &log, false, NULL, __func__, __LINE__, &tv);
        }
}

static int
rack_chg_query(struct tcpcb *tp, struct tcp_query_resp *reqr)
{
        struct tcp_rack *rack;
        struct rack_sendmap *rsm;
        int i;


        rack = (struct tcp_rack *)tp->t_fb_ptr;
        switch (reqr->req) {
        case TCP_QUERY_SENDMAP:
                if ((reqr->req_param == tp->snd_max) ||
                    (tp->snd_max == tp->snd_una)){
                        /* Unlikely */
                        return (0);
                }
                rsm = tqhash_find(rack->r_ctl.tqh, reqr->req_param);
                if (rsm == NULL) {
                        /* Can't find that seq -- unlikely */
                        return (0);
                }
                reqr->sendmap_start = rsm->r_start;
                reqr->sendmap_end = rsm->r_end;
                reqr->sendmap_send_cnt = rsm->r_rtr_cnt;
                reqr->sendmap_fas = rsm->r_fas;
                if (reqr->sendmap_send_cnt > SNDMAP_NRTX)
                        reqr->sendmap_send_cnt = SNDMAP_NRTX;
                for(i=0; i<reqr->sendmap_send_cnt; i++)
                        reqr->sendmap_time[i] = rsm->r_tim_lastsent[i];
                reqr->sendmap_ack_arrival = rsm->r_ack_arrival;
                reqr->sendmap_flags = rsm->r_flags & SNDMAP_MASK;
                reqr->sendmap_r_rtr_bytes = rsm->r_rtr_bytes;
                reqr->sendmap_dupacks = rsm->r_dupack;
                rack_log_chg_info(tp, rack, 1,
                                  rsm->r_start,
                                  rsm->r_end,
                                  rsm->r_flags);
                return(1);
                break;
        case TCP_QUERY_TIMERS_UP:
                if (rack->r_ctl.rc_hpts_flags == 0) {
                        /* no timers up */
                        return (0);
                }
                reqr->timer_hpts_flags = rack->r_ctl.rc_hpts_flags;
                if (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) {
                        reqr->timer_pacing_to = rack->r_ctl.rc_last_output_to;
                }
                if (rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK) {
                        reqr->timer_timer_exp = rack->r_ctl.rc_timer_exp;
                }
                rack_log_chg_info(tp, rack, 2,
                                  rack->r_ctl.rc_hpts_flags,
                                  rack->r_ctl.rc_last_output_to,
                                  rack->r_ctl.rc_timer_exp);
                return (1);
                break;
        case TCP_QUERY_RACK_TIMES:
                /* Reordering items */
                reqr->rack_num_dsacks = rack->r_ctl.num_dsack;
                reqr->rack_reorder_ts = rack->r_ctl.rc_reorder_ts;
                /* Timerstamps and timers */
                reqr->rack_rxt_last_time = rack->r_ctl.rc_tlp_rxt_last_time;
                reqr->rack_min_rtt = rack->r_ctl.rc_rack_min_rtt;
                reqr->rack_rtt = rack->rc_rack_rtt;
                reqr->rack_tmit_time = rack->r_ctl.rc_rack_tmit_time;
                reqr->rack_srtt_measured = rack->rc_srtt_measure_made;
                /* PRR data */
                reqr->rack_sacked = rack->r_ctl.rc_sacked;
                reqr->rack_holes_rxt = rack->r_ctl.rc_holes_rxt;
                reqr->rack_prr_delivered = rack->r_ctl.rc_prr_delivered;
                reqr->rack_prr_recovery_fs = rack->r_ctl.rc_prr_recovery_fs;
                reqr->rack_prr_sndcnt = rack->r_ctl.rc_prr_sndcnt;
                reqr->rack_prr_out = rack->r_ctl.rc_prr_out;
                /* TLP and persists info */
                reqr->rack_tlp_out = rack->rc_tlp_in_progress;
                reqr->rack_tlp_cnt_out = rack->r_ctl.rc_tlp_cnt_out;
                if (rack->rc_in_persist) {
                        reqr->rack_time_went_idle = rack->r_ctl.rc_went_idle_time;
                        reqr->rack_in_persist = 1;
                } else {
                        reqr->rack_time_went_idle = 0;
                        reqr->rack_in_persist = 0;
                }
                if (rack->r_wanted_output)
                        reqr->rack_wanted_output = 1;
                else
                        reqr->rack_wanted_output = 0;
                return (1);
                break;
        default:
                return (-EINVAL);
        }
}

static void
rack_switch_failed(struct tcpcb *tp)
{
        /*
         * This method gets called if a stack switch was
         * attempted and it failed. We are left
         * but our hpts timers were stopped and we
         * need to validate time units and t_flags2.
         */
        struct tcp_rack *rack;
        struct timeval tv;
        uint32_t cts;
        uint32_t toval;
        struct hpts_diag diag;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        tcp_change_time_units(tp, TCP_TMR_GRANULARITY_USEC);
        if  (rack->r_mbuf_queue || rack->rc_always_pace || rack->r_use_cmp_ack)
                tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
        else
                tp->t_flags2 &= ~TF2_SUPPORTS_MBUFQ;
        if (rack->r_use_cmp_ack && TCPS_HAVEESTABLISHED(tp->t_state))
                tp->t_flags2 |= TF2_MBUF_ACKCMP;
        if (tp->t_in_hpts > IHPTS_NONE) {
                /* Strange */
                return;
        }
        cts = tcp_get_usecs(&tv);
        if (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) {
                if (TSTMP_GT(rack->r_ctl.rc_last_output_to, cts)) {
                        toval = rack->r_ctl.rc_last_output_to - cts;
                } else {
                        /* one slot please */
                        toval = HPTS_USECS_PER_SLOT;
                }
        } else if (rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK) {
                if (TSTMP_GT(rack->r_ctl.rc_timer_exp, cts)) {
                        toval = rack->r_ctl.rc_timer_exp - cts;
                } else {
                        /* one slot please */
                        toval = HPTS_USECS_PER_SLOT;
                }
        } else
                toval = HPTS_USECS_PER_SLOT;
        tcp_hpts_insert(tp, toval, &diag);
        rack_log_hpts_diag(rack, cts, &diag, &tv);
}

static int
rack_init_outstanding(struct tcpcb *tp, struct tcp_rack *rack, uint32_t us_cts, void *ptr)
{
        struct rack_sendmap *rsm, *ersm;
        int insret __diagused;
        /*
         * When initing outstanding, we must be quite careful
         * to not refer to tp->t_fb_ptr. This has the old rack
         * pointer in it, not the "new" one (when we are doing
         * a stack switch).
         */


        if (tp->t_fb->tfb_chg_query == NULL) {
                /* Create a send map for the current outstanding data */

                rsm = rack_alloc(rack);
                if (rsm == NULL) {
                        uma_zfree(rack_pcb_zone, ptr);
                        return (ENOMEM);
                }
                rsm->r_no_rtt_allowed = 1;
                rsm->r_tim_lastsent[0] = rack_to_usec_ts(&rack->r_ctl.act_rcv_time);
                rsm->r_rtr_cnt = 1;
                rsm->r_rtr_bytes = 0;
                if (tp->t_flags & TF_SENTFIN)
                        rsm->r_flags |= RACK_HAS_FIN;
                rsm->r_end = tp->snd_max;
                if (tp->snd_una == tp->iss) {
                        /* The data space is one beyond snd_una */
                        rsm->r_flags |= RACK_HAS_SYN;
                        rsm->r_start = tp->iss;
                        rsm->r_end = rsm->r_start + (tp->snd_max - tp->snd_una);
                } else
                        rsm->r_start = tp->snd_una;
                rsm->r_dupack = 0;
                if (rack->rc_inp->inp_socket->so_snd.sb_mb != NULL) {
                        rsm->m = sbsndmbuf(&rack->rc_inp->inp_socket->so_snd, 0, &rsm->soff);
                        if (rsm->m) {
                                rsm->orig_m_len = rsm->m->m_len;
                                rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                        } else {
                                rsm->orig_m_len = 0;
                                rsm->orig_t_space = 0;
                        }
                } else {
                        /*
                         * This can happen if we have a stand-alone FIN or
                         *  SYN.
                         */
                        rsm->m = NULL;
                        rsm->orig_m_len = 0;
                        rsm->orig_t_space = 0;
                        rsm->soff = 0;
                }
#ifdef INVARIANTS
                if ((insret = tqhash_insert(rack->r_ctl.tqh, rsm)) != 0) {
                        panic("Insert in tailq_hash fails ret:%d rack:%p rsm:%p",
                              insret, rack, rsm);
                }
#else
                (void)tqhash_insert(rack->r_ctl.tqh, rsm);
#endif
                TAILQ_INSERT_TAIL(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                rsm->r_in_tmap = 1;
        } else {
                /* We have a query mechanism, lets use it */
                struct tcp_query_resp qr;
                int i;
                tcp_seq at;

                at = tp->snd_una;
                while (at != tp->snd_max) {
                        memset(&qr, 0, sizeof(qr));
                        qr.req = TCP_QUERY_SENDMAP;
                        qr.req_param = at;
                        if ((*tp->t_fb->tfb_chg_query)(tp, &qr) == 0)
                                break;
                        /* Move forward */
                        at = qr.sendmap_end;
                        /* Now lets build the entry for this one */
                        rsm = rack_alloc(rack);
                        if (rsm == NULL) {
                                uma_zfree(rack_pcb_zone, ptr);
                                return (ENOMEM);
                        }
                        memset(rsm, 0, sizeof(struct rack_sendmap));
                        /* Now configure the rsm and insert it */
                        rsm->r_dupack = qr.sendmap_dupacks;
                        rsm->r_start = qr.sendmap_start;
                        rsm->r_end = qr.sendmap_end;
                        if (qr.sendmap_fas)
                                rsm->r_fas = qr.sendmap_end;
                        else
                                rsm->r_fas = rsm->r_start - tp->snd_una;
                        /*
                         * We have carefully aligned the bits
                         * so that all we have to do is copy over
                         * the bits with the mask.
                         */
                        rsm->r_flags = qr.sendmap_flags & SNDMAP_MASK;
                        rsm->r_rtr_bytes = qr.sendmap_r_rtr_bytes;
                        rsm->r_rtr_cnt = qr.sendmap_send_cnt;
                        rsm->r_ack_arrival = qr.sendmap_ack_arrival;
                        for (i=0 ; i<rsm->r_rtr_cnt; i++)
                                rsm->r_tim_lastsent[i]  = qr.sendmap_time[i];
                        rsm->m = sbsndmbuf(&rack->rc_inp->inp_socket->so_snd,
                                           (rsm->r_start - tp->snd_una), &rsm->soff);
                        if (rsm->m) {
                                rsm->orig_m_len = rsm->m->m_len;
                                rsm->orig_t_space = M_TRAILINGROOM(rsm->m);
                        } else {
                                rsm->orig_m_len = 0;
                                rsm->orig_t_space = 0;
                        }
#ifdef INVARIANTS
                        if ((insret = tqhash_insert(rack->r_ctl.tqh, rsm)) != 0) {
                                panic("Insert in tailq_hash fails ret:%d rack:%p rsm:%p",
                                      insret, rack, rsm);
                        }
#else
                        (void)tqhash_insert(rack->r_ctl.tqh, rsm);
#endif
                        if ((rsm->r_flags & RACK_ACKED) == 0)  {
                                TAILQ_FOREACH(ersm, &rack->r_ctl.rc_tmap, r_tnext) {
                                        if (ersm->r_tim_lastsent[(ersm->r_rtr_cnt-1)] >
                                            rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)]) {
                                                /*
                                                 * If the existing ersm was sent at
                                                 * a later time than the new one, then
                                                 * the new one should appear ahead of this
                                                 * ersm.
                                                 */
                                                rsm->r_in_tmap = 1;
                                                TAILQ_INSERT_BEFORE(ersm, rsm, r_tnext);
                                                break;
                                        }
                                }
                                if (rsm->r_in_tmap == 0) {
                                        /*
                                         * Not found so shove it on the tail.
                                         */
                                        TAILQ_INSERT_TAIL(&rack->r_ctl.rc_tmap, rsm, r_tnext);
                                        rsm->r_in_tmap = 1;
                                }
                        } else {
                                if ((rack->r_ctl.rc_sacklast == NULL) ||
                                    (SEQ_GT(rsm->r_end, rack->r_ctl.rc_sacklast->r_end))) {
                                        rack->r_ctl.rc_sacklast = rsm;
                                }
                        }
                        rack_log_chg_info(tp, rack, 3,
                                          rsm->r_start,
                                          rsm->r_end,
                                          rsm->r_flags);
                }
        }
        return (0);
}


static int32_t
rack_init(struct tcpcb *tp, void **ptr)
{
        struct inpcb *inp = tptoinpcb(tp);
        struct tcp_rack *rack = NULL;
        uint32_t iwin, snt, us_cts;
        size_t sz;
        int err, no_query;

        tcp_hpts_init(tp);

        /*
         * First are we the initial or are we a switched stack?
         * If we are initing via tcp_newtcppcb the ptr passed
         * will be tp->t_fb_ptr. If its a stack switch that
         * has a previous stack we can query it will be a local
         * var that will in the end be set into t_fb_ptr.
         */
        if (ptr == &tp->t_fb_ptr)
                no_query = 1;
        else
                no_query = 0;
        *ptr = uma_zalloc(rack_pcb_zone, M_NOWAIT);
        if (*ptr == NULL) {
                /*
                 * We need to allocate memory but cant. The INP and INP_INFO
                 * locks and they are recursive (happens during setup. So a
                 * scheme to drop the locks fails :(
                 *
                 */
                return(ENOMEM);
        }
        memset(*ptr, 0, sizeof(struct tcp_rack));
        rack = (struct tcp_rack *)*ptr;
        rack->r_ctl.tqh = malloc(sizeof(struct tailq_hash), M_TCPFSB, M_NOWAIT);
        if (rack->r_ctl.tqh == NULL) {
                uma_zfree(rack_pcb_zone, rack);
                return(ENOMEM);
        }
        tqhash_init(rack->r_ctl.tqh);
        TAILQ_INIT(&rack->r_ctl.rc_free);
        TAILQ_INIT(&rack->r_ctl.rc_tmap);
        rack->rc_tp = tp;
        rack->rc_inp = inp;
        /* Set the flag */
        rack->r_is_v6 = (inp->inp_vflag & INP_IPV6) != 0;
        /* Probably not needed but lets be sure */
        rack_clear_rate_sample(rack);
        /*
         * Save off the default values, socket options will poke
         * at these if pacing is not on or we have not yet
         * reached where pacing is on (gp_ready/fixed enabled).
         * When they get set into the CC module (when gp_ready
         * is enabled or we enable fixed) then we will set these
         * values into the CC and place in here the old values
         * so we have a restoral. Then we will set the flag
         * rc_pacing_cc_set. That way whenever we turn off pacing
         * or switch off this stack, we will know to go restore
         * the saved values.
         *
         * We specifically put into the beta the ecn value for pacing.
         */
        rack->rc_new_rnd_needed = 1;
        rack->r_ctl.rc_split_limit = V_tcp_map_split_limit;
        /* We want abe like behavior as well */

        rack->r_ctl.rc_reorder_fade = rack_reorder_fade;
        rack->rc_allow_data_af_clo = rack_ignore_data_after_close;
        rack->r_ctl.rc_tlp_threshold = rack_tlp_thresh;
        if (rack_fill_cw_state)
                rack->rc_pace_to_cwnd = 1;
        if (rack_pacing_min_seg)
                rack->r_ctl.rc_user_set_min_segs = rack_pacing_min_seg;
        if (use_rack_rr)
                rack->use_rack_rr = 1;
        if (rack_dnd_default) {
                rack->rc_pace_dnd = 1;
        }
        if (V_tcp_delack_enabled)
                tp->t_delayed_ack = 1;
        else
                tp->t_delayed_ack = 0;
#ifdef TCP_ACCOUNTING
        if (rack_tcp_accounting) {
                tp->t_flags2 |= TF2_TCP_ACCOUNTING;
        }
#endif
        rack->r_ctl.pcm_i.cnt_alloc = RACK_DEFAULT_PCM_ARRAY;
        sz = (sizeof(struct rack_pcm_stats) * rack->r_ctl.pcm_i.cnt_alloc);
        rack->r_ctl.pcm_s = malloc(sz,M_TCPPCM, M_NOWAIT);
        if (rack->r_ctl.pcm_s == NULL) {
                rack->r_ctl.pcm_i.cnt_alloc = 0;
        }
        rack->r_ctl.rack_per_upper_bound_ss = (uint8_t)rack_per_upper_bound_ss;
        rack->r_ctl.rack_per_upper_bound_ca = (uint8_t)rack_per_upper_bound_ca;
        if (rack_enable_shared_cwnd)
                rack->rack_enable_scwnd = 1;
        rack->r_ctl.pace_len_divisor = rack_default_pacing_divisor;
        rack->rc_user_set_max_segs = rack_hptsi_segments;
        rack->r_ctl.max_reduction = rack_max_reduce;
        rack->rc_force_max_seg = 0;
        TAILQ_INIT(&rack->r_ctl.opt_list);
        rack->r_ctl.rc_saved_beta = V_newreno_beta_ecn;
        rack->r_ctl.rc_saved_beta_ecn = V_newreno_beta_ecn;
        if (rack_hibeta_setting) {
                rack->rack_hibeta = 1;
                if ((rack_hibeta_setting >= 50) &&
                    (rack_hibeta_setting <= 100)) {
                        rack->r_ctl.rc_saved_beta = rack_hibeta_setting;
                        rack->r_ctl.saved_hibeta = rack_hibeta_setting;
                }
        } else {
                rack->r_ctl.saved_hibeta = 50;
        }
        /*
         * We initialize to all ones so we never match 0
         * just in case the client sends in 0, it hopefully
         * will never have all 1's in ms :-)
         */
        rack->r_ctl.last_tm_mark = 0xffffffffffffffff;
        rack->r_ctl.rc_reorder_shift = rack_reorder_thresh;
        rack->r_ctl.rc_pkt_delay = rack_pkt_delay;
        rack->r_ctl.rc_tlp_cwnd_reduce = rack_lower_cwnd_at_tlp;
        rack->r_ctl.rc_lowest_us_rtt = 0xffffffff;
        rack->r_ctl.rc_highest_us_rtt = 0;
        rack->r_ctl.bw_rate_cap = rack_bw_rate_cap;
        rack->pcm_enabled = rack_pcm_is_enabled;
        if (rack_fillcw_bw_cap)
                rack->r_ctl.fillcw_cap = rack_fillcw_bw_cap;
        rack->r_ctl.timer_slop = TICKS_2_USEC(tcp_rexmit_slop);
        if (rack_use_cmp_acks)
                rack->r_use_cmp_ack = 1;
        if (rack_disable_prr)
                rack->rack_no_prr = 1;
        if (rack_gp_no_rec_chg)
                rack->rc_gp_no_rec_chg = 1;
        if (rack_pace_every_seg && tcp_can_enable_pacing()) {
                rack->r_ctl.pacing_method |= RACK_REG_PACING;
                rack->rc_always_pace = 1;
                if (rack->rack_hibeta)
                        rack_set_cc_pacing(rack);
        } else
                rack->rc_always_pace = 0;
        if (rack_enable_mqueue_for_nonpaced || rack->r_use_cmp_ack)
                rack->r_mbuf_queue = 1;
        else
                rack->r_mbuf_queue = 0;
        rack_set_pace_segments(tp, rack, __LINE__, NULL);
        if (rack_limits_scwnd)
                rack->r_limit_scw = 1;
        else
                rack->r_limit_scw = 0;
        rack_init_retransmit_value(rack, rack_rxt_controls);
        rack->rc_labc = V_tcp_abc_l_var;
        if (rack_honors_hpts_min_to)
                rack->r_use_hpts_min = 1;
        if (tp->snd_una != 0) {
                rack->rc_sendvars_notset = 0;
                /*
                 * Make sure any TCP timers are not running.
                 */
                tcp_timer_stop(tp);
        } else {
                /*
                 * Server side, we are called from the
                 * syn-cache. This means none of the
                 * snd_una/max are set yet so we have
                 * to defer this until the first send.
                 */
                rack->rc_sendvars_notset = 1;
        }

        rack->r_ctl.rc_rate_sample_method = rack_rate_sample_method;
        rack->rack_tlp_threshold_use = rack_tlp_threshold_use;
        rack->r_ctl.rc_prr_sendalot = rack_send_a_lot_in_prr;
        rack->r_ctl.rc_min_to = rack_min_to;
        microuptime(&rack->r_ctl.act_rcv_time);
        rack->r_ctl.rack_per_of_gp_ss = rack_per_of_gp_ss;
        if (rack_hw_up_only)
                rack->r_up_only = 1;
        if (rack_do_dyn_mul) {
                /* When dynamic adjustment is on CA needs to start at 100% */
                rack->rc_gp_dyn_mul = 1;
                if (rack_do_dyn_mul >= 100)
                        rack->r_ctl.rack_per_of_gp_ca = rack_do_dyn_mul;
        } else
                rack->r_ctl.rack_per_of_gp_ca = rack_per_of_gp_ca;
        rack->r_ctl.rack_per_of_gp_rec = rack_per_of_gp_rec;
        if (rack_timely_off) {
                rack->rc_skip_timely = 1;
        }
        if (rack->rc_skip_timely) {
                rack->r_ctl.rack_per_of_gp_rec = 90;
                rack->r_ctl.rack_per_of_gp_ca = 100;
                rack->r_ctl.rack_per_of_gp_ss = 250;
        }
        rack->r_ctl.rack_per_of_gp_probertt = rack_per_of_gp_probertt;
        rack->r_ctl.rc_tlp_rxt_last_time = tcp_tv_to_msec(&rack->r_ctl.act_rcv_time);
        rack->r_ctl.last_rcv_tstmp_for_rtt = tcp_tv_to_msec(&rack->r_ctl.act_rcv_time);

        setup_time_filter_small(&rack->r_ctl.rc_gp_min_rtt, FILTER_TYPE_MIN,
                                rack_probertt_filter_life);
        us_cts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
        rack->r_ctl.rc_lower_rtt_us_cts = us_cts;
        rack->r_ctl.rc_time_of_last_probertt = us_cts;
        rack->r_ctl.rc_went_idle_time = us_cts;
        rack->r_ctl.rc_time_probertt_starts = 0;

        rack->r_ctl.gp_rnd_thresh = rack_rnd_cnt_req & 0xff;
        if (rack_rnd_cnt_req  & 0x10000)
                rack->r_ctl.gate_to_fs = 1;
        rack->r_ctl.gp_gain_req = rack_gp_gain_req;
        if ((rack_rnd_cnt_req & 0x100) > 0) {

        }
        if (rack_dsack_std_based & 0x1) {
                /* Basically this means all rack timers are at least (srtt + 1/4 srtt) */
                rack->rc_rack_tmr_std_based = 1;
        }
        if (rack_dsack_std_based & 0x2) {
                /* Basically this means  rack timers are extended based on dsack by up to (2 * srtt) */
                rack->rc_rack_use_dsack = 1;
        }
        /* We require at least one measurement, even if the sysctl is 0 */
        if (rack_req_measurements)
                rack->r_ctl.req_measurements = rack_req_measurements;
        else
                rack->r_ctl.req_measurements = 1;
        if (rack_enable_hw_pacing)
                rack->rack_hdw_pace_ena = 1;
        if (rack_hw_rate_caps)
                rack->r_rack_hw_rate_caps = 1;
        if (rack_non_rxt_use_cr)
                rack->rack_rec_nonrxt_use_cr = 1;
        /* Lets setup the fsb block */
        err = rack_init_fsb(tp, rack);
        if (err) {
                uma_zfree(rack_pcb_zone, *ptr);
                *ptr = NULL;
                return (err);
        }
        if (rack_do_hystart) {
                tp->t_ccv.flags |= CCF_HYSTART_ALLOWED;
                if (rack_do_hystart > 1)
                        tp->t_ccv.flags |= CCF_HYSTART_CAN_SH_CWND;
                if (rack_do_hystart > 2)
                        tp->t_ccv.flags |= CCF_HYSTART_CONS_SSTH;
        }
        /* Log what we will do with queries */
        rack_log_chg_info(tp, rack, 7,
                          no_query, 0, 0);
        if (rack_def_profile)
                rack_set_profile(rack, rack_def_profile);
        /* Cancel the GP measurement in progress */
        tp->t_flags &= ~TF_GPUTINPROG;
        if ((tp->t_state != TCPS_CLOSED) &&
            (tp->t_state != TCPS_TIME_WAIT)) {
                /*
                 * We are already open, we may
                 * need to adjust a few things.
                 */
                if (SEQ_GT(tp->snd_max, tp->iss))
                        snt = tp->snd_max - tp->iss;
                else
                        snt = 0;
                iwin = rc_init_window(rack);
                if ((snt < iwin) &&
                    (no_query == 1)) {
                        /* We are not past the initial window
                         * on the first init (i.e. a stack switch
                         * has not yet occured) so we need to make
                         * sure cwnd and ssthresh is correct.
                         */
                        if (tp->snd_cwnd < iwin)
                                tp->snd_cwnd = iwin;
                        /*
                         * If we are within the initial window
                         * we want ssthresh to be unlimited. Setting
                         * it to the rwnd (which the default stack does
                         * and older racks) is not really a good idea
                         * since we want to be in SS and grow both the
                         * cwnd and the rwnd (via dynamic rwnd growth). If
                         * we set it to the rwnd then as the peer grows its
                         * rwnd we will be stuck in CA and never hit SS.
                         *
                         * Its far better to raise it up high (this takes the
                         * risk that there as been a loss already, probably
                         * we should have an indicator in all stacks of loss
                         * but we don't), but considering the normal use this
                         * is a risk worth taking. The consequences of not
                         * hitting SS are far worse than going one more time
                         * into it early on (before we have sent even a IW).
                         * It is highly unlikely that we will have had a loss
                         * before getting the IW out.
                         */
                        tp->snd_ssthresh = 0xffffffff;
                }
                /*
                 * Any init based on sequence numbers
                 * should be done in the deferred init path
                 * since we can be CLOSED and not have them
                 * inited when rack_init() is called. We
                 * are not closed so lets call it.
                 */
                rack_deferred_init(tp, rack);
        }
        if ((tp->t_state != TCPS_CLOSED) &&
            (tp->t_state != TCPS_TIME_WAIT) &&
            (no_query == 0) &&
            (tp->snd_una != tp->snd_max))  {
                err = rack_init_outstanding(tp, rack, us_cts, *ptr);
                if (err) {
                        *ptr = NULL;
                        return(err);
                }
        }
        rack_stop_all_timers(tp, rack);
        /* Setup all the t_flags2 */
        if  (rack->r_mbuf_queue || rack->rc_always_pace || rack->r_use_cmp_ack)
                tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
        else
                tp->t_flags2 &= ~TF2_SUPPORTS_MBUFQ;
        if (rack->r_use_cmp_ack && TCPS_HAVEESTABLISHED(tp->t_state))
                tp->t_flags2 |= TF2_MBUF_ACKCMP;
        /*
         * Timers in Rack are kept in microseconds so lets
         * convert any initial incoming variables
         * from ticks into usecs. Note that we
         * also change the values of t_srtt and t_rttvar, if
         * they are non-zero. They are kept with a 5
         * bit decimal so we have to carefully convert
         * these to get the full precision.
         */
        rack_convert_rtts(tp);
        rack_log_hystart_event(rack, rack->r_ctl.roundends, 20);
        if ((tp->t_flags & TF_DISCONNECTED) == 0) {
                /* We do not start any timers on disconnected connections */
                if (tp->t_fb->tfb_chg_query == NULL) {
                        rack_start_hpts_timer(rack, tp, tcp_get_usecs(NULL), 0, 0, 0);
                } else {
                        struct tcp_query_resp qr;
                        int ret;

                        memset(&qr, 0, sizeof(qr));

                        /* Get the misc time stamps and such for rack */
                        qr.req = TCP_QUERY_RACK_TIMES;
                        ret = (*tp->t_fb->tfb_chg_query)(tp, &qr);
                        if (ret == 1) {
                                rack->r_ctl.rc_reorder_ts = qr.rack_reorder_ts;
                                rack->r_ctl.num_dsack  = qr.rack_num_dsacks;
                                rack->r_ctl.rc_tlp_rxt_last_time = qr.rack_rxt_last_time;
                                rack->r_ctl.rc_rack_min_rtt = qr.rack_min_rtt;
                                rack->rc_rack_rtt = qr.rack_rtt;
                                rack->r_ctl.rc_rack_tmit_time = qr.rack_tmit_time;
                                rack->r_ctl.rc_sacked = qr.rack_sacked;
                                rack->r_ctl.rc_holes_rxt = qr.rack_holes_rxt;
                                rack->r_ctl.rc_prr_delivered = qr.rack_prr_delivered;
                                rack->r_ctl.rc_prr_recovery_fs = qr.rack_prr_recovery_fs;
                                rack->r_ctl.rc_prr_sndcnt = qr.rack_prr_sndcnt;
                                rack->r_ctl.rc_prr_out = qr.rack_prr_out;
                                if (qr.rack_tlp_out) {
                                        rack->rc_tlp_in_progress = 1;
                                        rack->r_ctl.rc_tlp_cnt_out = qr.rack_tlp_cnt_out;
                                } else {
                                        rack->rc_tlp_in_progress = 0;
                                        rack->r_ctl.rc_tlp_cnt_out = 0;
                                }
                                if (qr.rack_srtt_measured)
                                        rack->rc_srtt_measure_made = 1;
                                if (qr.rack_in_persist == 1) {
                                        rack->r_ctl.rc_went_idle_time = qr.rack_time_went_idle;
#ifdef NETFLIX_SHARED_CWND
                                        if (rack->r_ctl.rc_scw) {
                                                tcp_shared_cwnd_idle(rack->r_ctl.rc_scw, rack->r_ctl.rc_scw_index);
                                                rack->rack_scwnd_is_idle = 1;
                                        }
#endif
                                        rack->r_ctl.persist_lost_ends = 0;
                                        rack->probe_not_answered = 0;
                                        rack->forced_ack = 0;
                                        tp->t_rxtshift = 0;
                                        rack->rc_in_persist = 1;
                                        RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                                                           rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
                                }
                                if (qr.rack_wanted_output)
                                        rack->r_wanted_output = 1;
                                rack_log_chg_info(tp, rack, 6,
                                                  qr.rack_min_rtt,
                                                  qr.rack_rtt,
                                                  qr.rack_reorder_ts);
                        }
                        /* Get the old stack timers */
                        qr.req_param = 0;
                        qr.req = TCP_QUERY_TIMERS_UP;
                        ret = (*tp->t_fb->tfb_chg_query)(tp, &qr);
                        if (ret) {
                                /*
                                 * non-zero return means we have a timer('s)
                                 * to start. Zero means no timer (no keepalive
                                 * I suppose).
                                 */
                                uint32_t tov = 0;

                                rack->r_ctl.rc_hpts_flags = qr.timer_hpts_flags;
                                if (qr.timer_hpts_flags & PACE_PKT_OUTPUT) {
                                        rack->r_ctl.rc_last_output_to = qr.timer_pacing_to;
                                        if (TSTMP_GT(qr.timer_pacing_to, us_cts))
                                                tov = qr.timer_pacing_to - us_cts;
                                        else
                                                tov = HPTS_USECS_PER_SLOT;
                                }
                                if (qr.timer_hpts_flags & PACE_TMR_MASK) {
                                        rack->r_ctl.rc_timer_exp = qr.timer_timer_exp;
                                        if (tov == 0) {
                                                if (TSTMP_GT(qr.timer_timer_exp, us_cts))
                                                        tov = qr.timer_timer_exp - us_cts;
                                                else
                                                        tov = HPTS_USECS_PER_SLOT;
                                        }
                                }
                                rack_log_chg_info(tp, rack, 4,
                                                  rack->r_ctl.rc_hpts_flags,
                                                  rack->r_ctl.rc_last_output_to,
                                                  rack->r_ctl.rc_timer_exp);
                                if (tov) {
                                        struct hpts_diag diag;

                                        tcp_hpts_insert(tp, tov, &diag);
                                        rack_log_hpts_diag(rack, us_cts, &diag, &rack->r_ctl.act_rcv_time);
                                }
                        }
                }
                rack_log_rtt_shrinks(rack,  us_cts,  tp->t_rxtcur,
                                     __LINE__, RACK_RTTS_INIT);
        }
        return (0);
}

static int
rack_handoff_ok(struct tcpcb *tp)
{
        if ((tp->t_state == TCPS_CLOSED) ||
            (tp->t_state == TCPS_LISTEN)) {
                /* Sure no problem though it may not stick */
                return (0);
        }
        if ((tp->t_state == TCPS_SYN_SENT) ||
            (tp->t_state == TCPS_SYN_RECEIVED)) {
                /*
                 * We really don't know if you support sack,
                 * you have to get to ESTAB or beyond to tell.
                 */
                return (EAGAIN);
        }
        if ((tp->t_flags & TF_SENTFIN) && ((tp->snd_max - tp->snd_una) > 1)) {
                /*
                 * Rack will only send a FIN after all data is acknowledged.
                 * So in this case we have more data outstanding. We can't
                 * switch stacks until either all data and only the FIN
                 * is left (in which case rack_init() now knows how
                 * to deal with that) <or> all is acknowledged and we
                 * are only left with incoming data, though why you
                 * would want to switch to rack after all data is acknowledged
                 * I have no idea (rrs)!
                 */
                return (EAGAIN);
        }
        if ((tp->t_flags & TF_SACK_PERMIT) || rack_sack_not_required){
                return (0);
        }
        /*
         * If we reach here we don't do SACK on this connection so we can
         * never do rack.
         */
        return (EINVAL);
}

static void
rack_fini(struct tcpcb *tp, int32_t tcb_is_purged)
{

        if (tp->t_fb_ptr) {
                uint32_t cnt_free = 0;
                struct tcp_rack *rack;
                struct rack_sendmap *rsm;

                tcp_handle_orphaned_packets(tp);
                tp->t_flags &= ~TF_FORCEDATA;
                rack = (struct tcp_rack *)tp->t_fb_ptr;
                rack_log_pacing_delay_calc(rack,
                                           0,
                                           0,
                                           0,
                                           rack_get_gp_est(rack), /* delRate */
                                           rack_get_lt_bw(rack), /* rttProp */
                                           20, __LINE__, NULL, 0);
#ifdef NETFLIX_SHARED_CWND
                if (rack->r_ctl.rc_scw) {
                        uint32_t limit;

                        if (rack->r_limit_scw)
                                limit = max(1, rack->r_ctl.rc_lowest_us_rtt);
                        else
                                limit = 0;
                        tcp_shared_cwnd_free_full(tp, rack->r_ctl.rc_scw,
                                                  rack->r_ctl.rc_scw_index,
                                                  limit);
                        rack->r_ctl.rc_scw = NULL;
                }
#endif
                if (rack->r_ctl.fsb.tcp_ip_hdr) {
                        free(rack->r_ctl.fsb.tcp_ip_hdr, M_TCPFSB);
                        rack->r_ctl.fsb.tcp_ip_hdr = NULL;
                        rack->r_ctl.fsb.th = NULL;
                }
                if (rack->rc_always_pace == 1) {
                        rack_remove_pacing(rack);
                }
                /* Clean up any options if they were not applied */
                while (!TAILQ_EMPTY(&rack->r_ctl.opt_list)) {
                        struct deferred_opt_list *dol;

                        dol = TAILQ_FIRST(&rack->r_ctl.opt_list);
                        TAILQ_REMOVE(&rack->r_ctl.opt_list, dol, next);
                        free(dol, M_TCPDO);
                }
                /* rack does not use force data but other stacks may clear it */
                if (rack->r_ctl.crte != NULL) {
                        tcp_rel_pacing_rate(rack->r_ctl.crte, tp);
                        rack->rack_hdrw_pacing = 0;
                        rack->r_ctl.crte = NULL;
                }
#ifdef TCP_BLACKBOX
                tcp_log_flowend(tp);
#endif
                /*
                 * Lets take a different approach to purging just
                 * get each one and free it like a cum-ack would and
                 * not use a foreach loop.
                 */
                rsm = tqhash_min(rack->r_ctl.tqh);
                while (rsm) {
                        tqhash_remove(rack->r_ctl.tqh, rsm, REMOVE_TYPE_CUMACK);
                        rack->r_ctl.rc_num_maps_alloced--;
                        uma_zfree(rack_zone, rsm);
                        rsm = tqhash_min(rack->r_ctl.tqh);
                }
                rsm = TAILQ_FIRST(&rack->r_ctl.rc_free);
                while (rsm) {
                        TAILQ_REMOVE(&rack->r_ctl.rc_free, rsm, r_tnext);
                        rack->r_ctl.rc_num_maps_alloced--;
                        rack->rc_free_cnt--;
                        cnt_free++;
                        uma_zfree(rack_zone, rsm);
                        rsm = TAILQ_FIRST(&rack->r_ctl.rc_free);
                }
                if (rack->r_ctl.pcm_s != NULL) {
                        free(rack->r_ctl.pcm_s, M_TCPPCM);
                        rack->r_ctl.pcm_s = NULL;
                        rack->r_ctl.pcm_i.cnt_alloc = 0;
                        rack->r_ctl.pcm_i.cnt = 0;
                }
                if ((rack->r_ctl.rc_num_maps_alloced > 0) &&
                    (tcp_bblogging_on(tp))) {
                        union tcp_log_stackspecific log;
                        struct timeval tv;

                        memset(&log, 0, sizeof(log));
                        log.u_bbr.flex8 = 10;
                        log.u_bbr.flex1 = rack->r_ctl.rc_num_maps_alloced;
                        log.u_bbr.flex2 = rack->rc_free_cnt;
                        log.u_bbr.flex3 = cnt_free;
                        log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                        rsm = tqhash_min(rack->r_ctl.tqh);
                        log.u_bbr.delRate = (uintptr_t)rsm;
                        rsm = TAILQ_FIRST(&rack->r_ctl.rc_free);
                        log.u_bbr.cur_del_rate = (uintptr_t)rsm;
                        log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                        log.u_bbr.pkt_epoch = __LINE__;
                        (void)tcp_log_event(tp, NULL, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK,
                                             0, &log, false, NULL, NULL, 0, &tv);
                }
                KASSERT((rack->r_ctl.rc_num_maps_alloced == 0),
                        ("rack:%p num_aloc:%u after freeing all?",
                         rack,
                         rack->r_ctl.rc_num_maps_alloced));
                rack->rc_free_cnt = 0;
                free(rack->r_ctl.tqh, M_TCPFSB);
                rack->r_ctl.tqh = NULL;
                uma_zfree(rack_pcb_zone, tp->t_fb_ptr);
                tp->t_fb_ptr = NULL;
        }
        /* Make sure snd_nxt is correctly set */
        tp->snd_nxt = tp->snd_max;
}

static void
rack_set_state(struct tcpcb *tp, struct tcp_rack *rack)
{
        if ((rack->r_state == TCPS_CLOSED) && (tp->t_state != TCPS_CLOSED)) {
                rack->r_is_v6 = (tptoinpcb(tp)->inp_vflag & INP_IPV6) != 0;
        }
        switch (tp->t_state) {
        case TCPS_SYN_SENT:
                rack->r_state = TCPS_SYN_SENT;
                rack->r_substate = rack_do_syn_sent;
                break;
        case TCPS_SYN_RECEIVED:
                rack->r_state = TCPS_SYN_RECEIVED;
                rack->r_substate = rack_do_syn_recv;
                break;
        case TCPS_ESTABLISHED:
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                rack->r_state = TCPS_ESTABLISHED;
                rack->r_substate = rack_do_established;
                break;
        case TCPS_CLOSE_WAIT:
                rack->r_state = TCPS_CLOSE_WAIT;
                rack->r_substate = rack_do_close_wait;
                break;
        case TCPS_FIN_WAIT_1:
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                rack->r_state = TCPS_FIN_WAIT_1;
                rack->r_substate = rack_do_fin_wait_1;
                break;
        case TCPS_CLOSING:
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                rack->r_state = TCPS_CLOSING;
                rack->r_substate = rack_do_closing;
                break;
        case TCPS_LAST_ACK:
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                rack->r_state = TCPS_LAST_ACK;
                rack->r_substate = rack_do_lastack;
                break;
        case TCPS_FIN_WAIT_2:
                rack->r_state = TCPS_FIN_WAIT_2;
                rack->r_substate = rack_do_fin_wait_2;
                break;
        case TCPS_LISTEN:
        case TCPS_CLOSED:
        case TCPS_TIME_WAIT:
        default:
                break;
        };
        if (rack->r_use_cmp_ack && TCPS_HAVEESTABLISHED(tp->t_state))
                rack->rc_tp->t_flags2 |= TF2_MBUF_ACKCMP;

}

static void
rack_timer_audit(struct tcpcb *tp, struct tcp_rack *rack, struct sockbuf *sb)
{
        /*
         * We received an ack, and then did not
         * call send or were bounced out due to the
         * hpts was running. Now a timer is up as well, is
         * it the right timer?
         */
        struct rack_sendmap *rsm;
        int tmr_up;

        tmr_up = rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK;
        if (tcp_in_hpts(rack->rc_tp) == 0) {
                /*
                 * Ok we probably need some timer up, but no
                 * matter what the mask we are not in hpts. We
                 * may have received an old ack and thus did nothing.
                 */
                rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
                rack_start_hpts_timer(rack, tp, tcp_get_usecs(NULL), 0, 0, 0);
                return;
        }
        if (rack->rc_in_persist && (tmr_up == PACE_TMR_PERSIT))
                return;
        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
        if (((rsm == NULL) || (tp->t_state < TCPS_ESTABLISHED)) &&
            (tmr_up == PACE_TMR_RXT)) {
                /* Should be an RXT */
                return;
        }
        if (rsm == NULL) {
                /* Nothing outstanding? */
                if (tp->t_flags & TF_DELACK) {
                        if (tmr_up == PACE_TMR_DELACK)
                                /* We are supposed to have delayed ack up and we do */
                                return;
                } else if (((V_tcp_always_keepalive ||
                             rack->rc_inp->inp_socket->so_options & SO_KEEPALIVE) &&
                            (tp->t_state <= TCPS_CLOSING)) &&
                           (tmr_up == PACE_TMR_KEEP) &&
                           (tp->snd_max == tp->snd_una)) {
                        /* We should have keep alive up and we do */
                        return;
                }
        }
        if (SEQ_GT(tp->snd_max, tp->snd_una) &&
                   ((tmr_up == PACE_TMR_TLP) ||
                    (tmr_up == PACE_TMR_RACK) ||
                    (tmr_up == PACE_TMR_RXT))) {
                /*
                 * Either a Rack, TLP or RXT is fine if  we
                 * have outstanding data.
                 */
                return;
        } else if (tmr_up == PACE_TMR_DELACK) {
                /*
                 * If the delayed ack was going to go off
                 * before the rtx/tlp/rack timer were going to
                 * expire, then that would be the timer in control.
                 * Note we don't check the time here trusting the
                 * code is correct.
                 */
                return;
        }
        /*
         * Ok the timer originally started is not what we want now.
         * We will force the hpts to be stopped if any, and restart
         * with the slot set to what was in the saved slot.
         */
        if (tcp_in_hpts(rack->rc_tp)) {
                if (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) {
                        uint32_t us_cts;

                        us_cts = tcp_get_usecs(NULL);
                        if (TSTMP_GT(rack->r_ctl.rc_last_output_to, us_cts)) {
                                rack->r_early = 1;
                                rack->r_ctl.rc_agg_early += (rack->r_ctl.rc_last_output_to - us_cts);
                        }
                        rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
                }
                tcp_hpts_remove(rack->rc_tp);
        }
        rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
        rack_start_hpts_timer(rack, tp, tcp_get_usecs(NULL), 0, 0, 0);
}


static void
rack_do_win_updates(struct tcpcb *tp, struct tcp_rack *rack, uint32_t tiwin, uint32_t seq, uint32_t ack, uint32_t cts)
{
        if ((SEQ_LT(tp->snd_wl1, seq) ||
            (tp->snd_wl1 == seq && (SEQ_LT(tp->snd_wl2, ack) ||
            (tp->snd_wl2 == ack && tiwin > tp->snd_wnd))))) {
                /* keep track of pure window updates */
                if ((tp->snd_wl2 == ack) && (tiwin > tp->snd_wnd))
                        KMOD_TCPSTAT_INC(tcps_rcvwinupd);
                tp->snd_wnd = tiwin;
                rack_validate_fo_sendwin_up(tp, rack);
                tp->snd_wl1 = seq;
                tp->snd_wl2 = ack;
                if (tp->snd_wnd > tp->max_sndwnd)
                        tp->max_sndwnd = tp->snd_wnd;
            rack->r_wanted_output = 1;
        } else if ((tp->snd_wl2 == ack) && (tiwin < tp->snd_wnd)) {
                tp->snd_wnd = tiwin;
                rack_validate_fo_sendwin_up(tp, rack);
                tp->snd_wl1 = seq;
                tp->snd_wl2 = ack;
        } else {
                /* Not a valid win update */
                return;
        }
        if (tp->snd_wnd > tp->max_sndwnd)
                tp->max_sndwnd = tp->snd_wnd;
        /* Do we exit persists? */
        if ((rack->rc_in_persist != 0) &&
            (tp->snd_wnd >= min((rack->r_ctl.rc_high_rwnd/2),
                                rack->r_ctl.rc_pace_min_segs))) {
                rack_exit_persist(tp, rack, cts);
        }
        /* Do we enter persists? */
        if ((rack->rc_in_persist == 0) &&
            (tp->snd_wnd < min((rack->r_ctl.rc_high_rwnd/2), rack->r_ctl.rc_pace_min_segs)) &&
            TCPS_HAVEESTABLISHED(tp->t_state) &&
            ((tp->snd_max == tp->snd_una) || rack->rc_has_collapsed) &&
            sbavail(&tptosocket(tp)->so_snd) &&
            (sbavail(&tptosocket(tp)->so_snd) > tp->snd_wnd)) {
                /*
                 * Here the rwnd is less than
                 * the pacing size, we are established,
                 * nothing is outstanding, and there is
                 * data to send. Enter persists.
                 */
                rack_enter_persist(tp, rack, rack->r_ctl.rc_rcvtime, ack);
        }
}

static void
rack_log_input_packet(struct tcpcb *tp, struct tcp_rack *rack, struct tcp_ackent *ae, int ackval, uint32_t high_seq)
{

        if (tcp_bblogging_on(rack->rc_tp)) {
                struct inpcb *inp = tptoinpcb(tp);
                union tcp_log_stackspecific log;
                struct timeval ltv;
                char tcp_hdr_buf[60];
                struct tcphdr *th;
                struct timespec ts;
                uint32_t orig_snd_una;
                uint8_t xx = 0;

#ifdef TCP_REQUEST_TRK
                struct tcp_sendfile_track *tcp_req;

                if (SEQ_GT(ae->ack, tp->snd_una)) {
                        tcp_req = tcp_req_find_req_for_seq(tp, (ae->ack-1));
                } else {
                        tcp_req = tcp_req_find_req_for_seq(tp, ae->ack);
                }
#endif
                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                if (rack->rack_no_prr == 0)
                        log.u_bbr.flex1 = rack->r_ctl.rc_prr_sndcnt;
                else
                        log.u_bbr.flex1 = 0;
                log.u_bbr.use_lt_bw = rack->r_ent_rec_ns;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->r_might_revert;
                log.u_bbr.flex2 = rack->r_ctl.rc_num_maps_alloced;
                log.u_bbr.bbr_state = rack->rc_free_cnt;
                log.u_bbr.inflight = ctf_flight_size(tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = tp->t_maxseg;
                log.u_bbr.flex4 = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.flex7 = 1;
                log.u_bbr.lost = ae->flags;
                log.u_bbr.cwnd_gain = ackval;
                log.u_bbr.pacing_gain = 0x2;
                if (ae->flags & TSTMP_HDWR) {
                        /* Record the hardware timestamp if present */
                        log.u_bbr.flex3 = M_TSTMP;
                        ts.tv_sec = ae->timestamp / 1000000000;
                        ts.tv_nsec = ae->timestamp % 1000000000;
                        ltv.tv_sec = ts.tv_sec;
                        ltv.tv_usec = ts.tv_nsec / 1000;
                        log.u_bbr.lt_epoch = tcp_tv_to_usec(&ltv);
                } else if (ae->flags & TSTMP_LRO) {
                        /* Record the LRO the arrival timestamp */
                        log.u_bbr.flex3 = M_TSTMP_LRO;
                        ts.tv_sec = ae->timestamp / 1000000000;
                        ts.tv_nsec = ae->timestamp % 1000000000;
                        ltv.tv_sec = ts.tv_sec;
                        ltv.tv_usec = ts.tv_nsec / 1000;
                        log.u_bbr.flex5 = tcp_tv_to_usec(&ltv);
                }
                log.u_bbr.timeStamp = tcp_get_usecs(&ltv);
                /* Log the rcv time */
                log.u_bbr.delRate = ae->timestamp;
#ifdef TCP_REQUEST_TRK
                log.u_bbr.applimited = tp->t_tcpreq_closed;
                log.u_bbr.applimited <<= 8;
                log.u_bbr.applimited |= tp->t_tcpreq_open;
                log.u_bbr.applimited <<= 8;
                log.u_bbr.applimited |= tp->t_tcpreq_req;
                if (tcp_req) {
                        /* Copy out any client req info */
                        /* seconds */
                        log.u_bbr.pkt_epoch = (tcp_req->localtime / HPTS_USEC_IN_SEC);
                        /* useconds */
                        log.u_bbr.delivered = (tcp_req->localtime % HPTS_USEC_IN_SEC);
                        log.u_bbr.rttProp = tcp_req->timestamp;
                        log.u_bbr.cur_del_rate = tcp_req->start;
                        if (tcp_req->flags & TCP_TRK_TRACK_FLG_OPEN) {
                                log.u_bbr.flex8 |= 1;
                        } else {
                                log.u_bbr.flex8 |= 2;
                                log.u_bbr.bw_inuse = tcp_req->end;
                        }
                        log.u_bbr.flex6 = tcp_req->start_seq;
                        if (tcp_req->flags & TCP_TRK_TRACK_FLG_COMP) {
                                log.u_bbr.flex8 |= 4;
                                log.u_bbr.epoch = tcp_req->end_seq;
                        }
                }
#endif
                memset(tcp_hdr_buf, 0, sizeof(tcp_hdr_buf));
                th = (struct tcphdr *)tcp_hdr_buf;
                th->th_seq = ae->seq;
                th->th_ack = ae->ack;
                th->th_win = ae->win;
                /* Now fill in the ports */
                th->th_sport = inp->inp_fport;
                th->th_dport = inp->inp_lport;
                tcp_set_flags(th, ae->flags);
                /* Now do we have a timestamp option? */
                if (ae->flags & HAS_TSTMP) {
                        u_char *cp;
                        uint32_t val;

                        th->th_off = ((sizeof(struct tcphdr) + TCPOLEN_TSTAMP_APPA) >> 2);
                        cp = (u_char *)(th + 1);
                        *cp = TCPOPT_NOP;
                        cp++;
                        *cp = TCPOPT_NOP;
                        cp++;
                        *cp = TCPOPT_TIMESTAMP;
                        cp++;
                        *cp = TCPOLEN_TIMESTAMP;
                        cp++;
                        val = htonl(ae->ts_value);
                        bcopy((char *)&val,
                              (char *)cp, sizeof(uint32_t));
                        val = htonl(ae->ts_echo);
                        bcopy((char *)&val,
                              (char *)(cp + 4), sizeof(uint32_t));
                } else
                        th->th_off = (sizeof(struct tcphdr) >> 2);

                /*
                 * For sane logging we need to play a little trick.
                 * If the ack were fully processed we would have moved
                 * snd_una to high_seq, but since compressed acks are
                 * processed in two phases, at this point (logging) snd_una
                 * won't be advanced. So we would see multiple acks showing
                 * the advancement. We can prevent that by "pretending" that
                 * snd_una was advanced and then un-advancing it so that the
                 * logging code has the right value for tlb_snd_una.
                 */
                if (tp->snd_una != high_seq) {
                        orig_snd_una = tp->snd_una;
                        tp->snd_una = high_seq;
                        xx = 1;
                } else
                        xx = 0;
                TCP_LOG_EVENTP(tp, th,
                               &tptosocket(tp)->so_rcv,
                               &tptosocket(tp)->so_snd, TCP_LOG_IN, 0,
                               0, &log, true, &ltv);
                if (xx) {
                        tp->snd_una = orig_snd_una;
                }
        }

}

static void
rack_handle_probe_response(struct tcp_rack *rack, uint32_t tiwin, uint32_t us_cts)
{
        uint32_t us_rtt;
        /*
         * A persist or keep-alive was forced out, update our
         * min rtt time. Note now worry about lost responses.
         * When a subsequent keep-alive or persist times out
         * and forced_ack is still on, then the last probe
         * was not responded to. In such cases we have a
         * sysctl that controls the behavior. Either we apply
         * the rtt but with reduced confidence (0). Or we just
         * plain don't apply the rtt estimate. Having data flow
         * will clear the probe_not_answered flag i.e. cum-ack
         * move forward <or> exiting and reentering persists.
         */

        rack->forced_ack = 0;
        rack->rc_tp->t_rxtshift = 0;
        if ((rack->rc_in_persist &&
             (tiwin == rack->rc_tp->snd_wnd)) ||
            (rack->rc_in_persist == 0)) {
                /*
                 * In persists only apply the RTT update if this is
                 * a response to our window probe. And that
                 * means the rwnd sent must match the current
                 * snd_wnd. If it does not, then we got a
                 * window update ack instead. For keepalive
                 * we allow the answer no matter what the window.
                 *
                 * Note that if the probe_not_answered is set then
                 * the forced_ack_ts is the oldest one i.e. the first
                 * probe sent that might have been lost. This assures
                 * us that if we do calculate an RTT it is longer not
                 * some short thing.
                 */
                if (rack->rc_in_persist)
                        counter_u64_add(rack_persists_acks, 1);
                us_rtt = us_cts - rack->r_ctl.forced_ack_ts;
                if (us_rtt == 0)
                        us_rtt = 1;
                if (rack->probe_not_answered == 0) {
                        rack_apply_updated_usrtt(rack, us_rtt, us_cts);
                        tcp_rack_xmit_timer(rack, us_rtt, 0, us_rtt, 3, NULL, 1);
                } else {
                        /* We have a retransmitted probe here too */
                        if (rack_apply_rtt_with_reduced_conf) {
                                rack_apply_updated_usrtt(rack, us_rtt, us_cts);
                                tcp_rack_xmit_timer(rack, us_rtt, 0, us_rtt, 0, NULL, 1);
                        }
                }
        }
}

static void
rack_new_round_starts(struct tcpcb *tp, struct tcp_rack *rack, uint32_t high_seq)
{
        /*
         * The next send has occurred mark the end of the round
         * as when that data gets acknowledged. We can
         * also do common things we might need to do when
         * a round begins.
         */
        rack->r_ctl.roundends = tp->snd_max;
        rack->rc_new_rnd_needed = 0;
        rack_log_hystart_event(rack, tp->snd_max, 4);
}


static void
rack_log_pcm(struct tcp_rack *rack, uint8_t mod, uint32_t flex1, uint32_t flex2,
             uint32_t flex3)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                (void)tcp_get_usecs(&tv);
                memset(&log, 0, sizeof(log));
                log.u_bbr.timeStamp = tcp_tv_to_usec(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.flex8 = mod;
                log.u_bbr.flex1 = flex1;
                log.u_bbr.flex2 = flex2;
                log.u_bbr.flex3 = flex3;
                log.u_bbr.flex4 = rack_pcm_every_n_rounds;
                log.u_bbr.flex5 = rack->r_ctl.pcm_idle_rounds;
                log.u_bbr.bbr_substate = rack->pcm_needed;
                log.u_bbr.bbr_substate <<= 1;
                log.u_bbr.bbr_substate |= rack->pcm_in_progress;
                log.u_bbr.bbr_substate <<= 1;
                log.u_bbr.bbr_substate |= rack->pcm_enabled; /* bits are NIE for Needed, Inprogress, Enabled */
                (void)tcp_log_event(rack->rc_tp, NULL, NULL, NULL, TCP_PCM_MEASURE, ERRNO_UNK,
                                    0, &log, false, NULL, NULL, 0, &tv);
        }
}

static void
rack_new_round_setup(struct tcpcb *tp, struct tcp_rack *rack, uint32_t high_seq)
{
        /*
         * The round (current_round) has ended. We now
         * setup for the next round by incrementing the
         * round numnber and doing any round specific
         * things.
         */
        rack_log_hystart_event(rack, high_seq, 21);
        rack->r_ctl.current_round++;
        /* New round (current_round) begins at next send */
        rack->rc_new_rnd_needed = 1;
        if ((rack->pcm_enabled == 1) &&
            (rack->pcm_needed == 0) &&
            (rack->pcm_in_progress == 0)) {
                /*
                 * If we have enabled PCM, then we need to
                 * check if the round has adanced to the state
                 * where one is required.
                 */
                int rnds;

                rnds = rack->r_ctl.current_round - rack->r_ctl.last_pcm_round;
                if ((rnds + rack->r_ctl.pcm_idle_rounds) >= rack_pcm_every_n_rounds) {
                        rack->pcm_needed = 1;
                        rack_log_pcm(rack, 3, rack->r_ctl.last_pcm_round, rack_pcm_every_n_rounds, rack->r_ctl.current_round );
                } else if (rack_verbose_logging) {
                        rack_log_pcm(rack, 3, rack->r_ctl.last_pcm_round, rack_pcm_every_n_rounds, rack->r_ctl.current_round );
                }
        }
        if (tp->t_ccv.flags & CCF_HYSTART_ALLOWED) {
                /* We have hystart enabled send the round info in */
                if (CC_ALGO(tp)->newround != NULL) {
                        CC_ALGO(tp)->newround(&tp->t_ccv, rack->r_ctl.current_round);
                }
        }
        /*
         * For DGP an initial startup check. We want to validate
         * that we are not just pushing on slow-start and just
         * not gaining.. i.e. filling buffers without getting any
         * boost in b/w during the inital slow-start.
         */
        if (rack->dgp_on &&
            (rack->rc_initial_ss_comp == 0) &&
            (tp->snd_cwnd < tp->snd_ssthresh) &&
            (rack->r_ctl.num_measurements >= RACK_REQ_AVG) &&
            (rack->r_ctl.gp_rnd_thresh > 0) &&
            ((rack->r_ctl.current_round - rack->r_ctl.last_rnd_of_gp_rise) >= rack->r_ctl.gp_rnd_thresh)) {

                /*
                 * We are in the initial SS and we have hd rack_rnd_cnt_req rounds(def:5) where
                 * we have not gained the required amount in the gp_est (120.0% aka 1200). Lets
                 * exit SS.
                 *
                 * Pick up the flight size now as we enter slowstart (not the
                 * cwnd which may be inflated).
                 */
                rack->rc_initial_ss_comp = 1;

                if (tcp_bblogging_on(rack->rc_tp)) {
                        union tcp_log_stackspecific log;
                        struct timeval tv;

                        memset(&log, 0, sizeof(log));
                        log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                        log.u_bbr.flex1 = rack->r_ctl.current_round;
                        log.u_bbr.flex2 = rack->r_ctl.last_rnd_of_gp_rise;
                        log.u_bbr.flex3 = rack->r_ctl.gp_rnd_thresh;
                        log.u_bbr.flex4 = rack->r_ctl.gate_to_fs;
                        log.u_bbr.flex5 = rack->r_ctl.ss_hi_fs;
                        log.u_bbr.flex8 = 40;
                        (void)tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_CWND, 0,
                                            0, &log, false, NULL, __func__, __LINE__,&tv);
                }
                if ((rack->r_ctl.gate_to_fs == 1) &&
                     (tp->snd_cwnd > rack->r_ctl.ss_hi_fs)) {
                        tp->snd_cwnd = rack->r_ctl.ss_hi_fs;
                }
                tp->snd_ssthresh = tp->snd_cwnd - 1;
                /* Turn off any fast output running */
                rack->r_fast_output = 0;
        }
}

static int
rack_do_compressed_ack_processing(struct tcpcb *tp, struct socket *so, struct mbuf *m, int nxt_pkt, struct timeval *tv)
{
        /*
         * Handle a "special" compressed ack mbuf. Each incoming
         * ack has only four possible dispositions:
         *
         * A) It moves the cum-ack forward
         * B) It is behind the cum-ack.
         * C) It is a window-update ack.
         * D) It is a dup-ack.
         *
         * Note that we can have between 1 -> TCP_COMP_ACK_ENTRIES
         * in the incoming mbuf. We also need to still pay attention
         * to nxt_pkt since there may be another packet after this
         * one.
         */
#ifdef TCP_ACCOUNTING
        uint64_t ts_val;
        uint64_t rdstc;
#endif
        int segsiz;
        struct timespec ts;
        struct tcp_rack *rack;
        struct tcp_ackent *ae;
        uint32_t tiwin, ms_cts, cts, acked, acked_amount, high_seq, win_seq, the_win, win_upd_ack;
        int cnt, i, did_out, ourfinisacked = 0;
        struct tcpopt to_holder, *to = NULL;
#ifdef TCP_ACCOUNTING
        int win_up_req = 0;
#endif
        int nsegs = 0;
        int under_pacing = 0;
        int post_recovery = 0;
#ifdef TCP_ACCOUNTING
        sched_pin();
#endif
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->gp_ready &&
            (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT))
                under_pacing = 1;

        if (rack->r_state != tp->t_state)
                rack_set_state(tp, rack);
        if ((tp->t_state >= TCPS_FIN_WAIT_1) &&
            (tp->t_flags & TF_GPUTINPROG)) {
                /*
                 * We have a goodput in progress
                 * and we have entered a late state.
                 * Do we have enough data in the sb
                 * to handle the GPUT request?
                 */
                uint32_t bytes;

                bytes = tp->gput_ack - tp->gput_seq;
                if (SEQ_GT(tp->gput_seq, tp->snd_una))
                        bytes += tp->gput_seq - tp->snd_una;
                if (bytes > sbavail(&tptosocket(tp)->so_snd)) {
                        /*
                         * There are not enough bytes in the socket
                         * buffer that have been sent to cover this
                         * measurement. Cancel it.
                         */
                        rack_log_pacing_delay_calc(rack, (tp->gput_ack - tp->gput_seq) /*flex2*/,
                                                   rack->r_ctl.rc_gp_srtt /*flex1*/,
                                                   tp->gput_seq,
                                                   0, 0, 18, __LINE__, NULL, 0);
                        tp->t_flags &= ~TF_GPUTINPROG;
                }
        }
        to = &to_holder;
        to->to_flags = 0;
        KASSERT((m->m_len >= sizeof(struct tcp_ackent)),
                ("tp:%p m_cmpack:%p with invalid len:%u", tp, m, m->m_len));
        cnt = m->m_len / sizeof(struct tcp_ackent);
        counter_u64_add(rack_multi_single_eq, cnt);
        high_seq = tp->snd_una;
        the_win = tp->snd_wnd;
        win_seq = tp->snd_wl1;
        win_upd_ack = tp->snd_wl2;
        cts = tcp_tv_to_usec(tv);
        ms_cts = tcp_tv_to_msec(tv);
        rack->r_ctl.rc_rcvtime = cts;
        segsiz = ctf_fixed_maxseg(tp);
        if ((rack->rc_gp_dyn_mul) &&
            (rack->use_fixed_rate == 0) &&
            (rack->rc_always_pace)) {
                /* Check in on probertt */
                rack_check_probe_rtt(rack, cts);
        }
        for (i = 0; i < cnt; i++) {
#ifdef TCP_ACCOUNTING
                ts_val = get_cyclecount();
#endif
                rack_clear_rate_sample(rack);
                ae = ((mtod(m, struct tcp_ackent *)) + i);
                if (ae->flags & TH_FIN)
                        rack_log_pacing_delay_calc(rack,
                                                   0,
                                                   0,
                                                   0,
                                                   rack_get_gp_est(rack), /* delRate */
                                                   rack_get_lt_bw(rack), /* rttProp */
                                                   20, __LINE__, NULL, 0);
                /* Setup the window */
                tiwin = ae->win << tp->snd_scale;
                if (tiwin > rack->r_ctl.rc_high_rwnd)
                        rack->r_ctl.rc_high_rwnd = tiwin;
                /* figure out the type of ack */
                if (SEQ_LT(ae->ack, high_seq)) {
                        /* Case B*/
                        ae->ack_val_set = ACK_BEHIND;
                } else if (SEQ_GT(ae->ack, high_seq)) {
                        /* Case A */
                        ae->ack_val_set = ACK_CUMACK;
                } else if ((tiwin == the_win) && (rack->rc_in_persist == 0)){
                        /* Case D */
                        ae->ack_val_set = ACK_DUPACK;
                } else {
                        /* Case C */
                        ae->ack_val_set = ACK_RWND;
                }
                rack_log_type_bbrsnd(rack, 0, 0, cts, tv, __LINE__);
                rack_log_input_packet(tp, rack, ae, ae->ack_val_set, high_seq);
                /* Validate timestamp */
                if (ae->flags & HAS_TSTMP) {
                        /* Setup for a timestamp */
                        to->to_flags = TOF_TS;
                        ae->ts_echo -= tp->ts_offset;
                        to->to_tsecr = ae->ts_echo;
                        to->to_tsval = ae->ts_value;
                        /*
                         * If echoed timestamp is later than the current time, fall back to
                         * non RFC1323 RTT calculation.  Normalize timestamp if syncookies
                         * were used when this connection was established.
                         */
                        if (TSTMP_GT(ae->ts_echo, ms_cts))
                                to->to_tsecr = 0;
                        if (tp->ts_recent &&
                            TSTMP_LT(ae->ts_value, tp->ts_recent)) {
                                if (ctf_ts_check_ac(tp, (ae->flags & 0xff))) {
#ifdef TCP_ACCOUNTING
                                        rdstc = get_cyclecount();
                                        if (rdstc > ts_val) {
                                                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                                        tp->tcp_proc_time[ae->ack_val_set] += (rdstc - ts_val);
                                                }
                                        }
#endif
                                        continue;
                                }
                        }
                        if (SEQ_LEQ(ae->seq, tp->last_ack_sent) &&
                            SEQ_LEQ(tp->last_ack_sent, ae->seq)) {
                                tp->ts_recent_age = tcp_ts_getticks();
                                tp->ts_recent = ae->ts_value;
                        }
                } else {
                        /* Setup for a no options */
                        to->to_flags = 0;
                }
                /* Update the rcv time and perform idle reduction possibly */
                if  (tp->t_idle_reduce &&
                     (tp->snd_max == tp->snd_una) &&
                     (TICKS_2_USEC(ticks - tp->t_rcvtime) >= tp->t_rxtcur)) {
                        counter_u64_add(rack_input_idle_reduces, 1);
                        rack_cc_after_idle(rack, tp);
                }
                tp->t_rcvtime = ticks;
                /* Now what about ECN of a chain of pure ACKs? */
                if (tcp_ecn_input_segment(tp, ae->flags, 0,
                        tcp_packets_this_ack(tp, ae->ack),
                        ae->codepoint))
                        rack_cong_signal(tp, CC_ECN, ae->ack, __LINE__);
                if (tp->t_flags & TF_ACKNOW)
                        rack->r_wanted_output = 1;
#ifdef TCP_ACCOUNTING
                /* Count for the specific type of ack in */
                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                        tp->tcp_cnt_counters[ae->ack_val_set]++;
                }
#endif
                /*
                 * Note how we could move up these in the determination
                 * above, but we don't so that way the timestamp checks (and ECN)
                 * is done first before we do any processing on the ACK.
                 * The non-compressed path through the code has this
                 * weakness (noted by @jtl) that it actually does some
                 * processing before verifying the timestamp information.
                 * We don't take that path here which is why we set
                 * the ack_val_set first, do the timestamp and ecn
                 * processing, and then look at what we have setup.
                 */
                if (ae->ack_val_set == ACK_BEHIND) {
                        /*
                         * Case B flag reordering, if window is not closed
                         * or it could be a keep-alive or persists
                         */
                        if (SEQ_LT(ae->ack, tp->snd_una) && (sbspace(&so->so_rcv) > segsiz)) {
                                rack->r_ctl.rc_reorder_ts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
                                if (rack->r_ctl.rc_reorder_ts == 0)
                                        rack->r_ctl.rc_reorder_ts = 1;
                        }
                } else if (ae->ack_val_set == ACK_DUPACK) {
                        /* Case D */
                        rack_strike_dupack(rack, ae->ack);
                } else if (ae->ack_val_set == ACK_RWND) {
                        /* Case C */
                        if ((ae->flags & TSTMP_LRO) || (ae->flags & TSTMP_HDWR)) {
                                ts.tv_sec = ae->timestamp / 1000000000;
                                ts.tv_nsec = ae->timestamp % 1000000000;
                                rack->r_ctl.act_rcv_time.tv_sec = ts.tv_sec;
                                rack->r_ctl.act_rcv_time.tv_usec = ts.tv_nsec/1000;
                        } else {
                                rack->r_ctl.act_rcv_time = *tv;
                        }
                        if (rack->forced_ack) {
                                rack_handle_probe_response(rack, tiwin,
                                                           tcp_tv_to_usec(&rack->r_ctl.act_rcv_time));
                        }
#ifdef TCP_ACCOUNTING
                        win_up_req = 1;
#endif
                        win_upd_ack = ae->ack;
                        win_seq = ae->seq;
                        the_win = tiwin;
                        rack_do_win_updates(tp, rack, the_win, win_seq, win_upd_ack, cts);
                } else {
                        /* Case A */
                        if (SEQ_GT(ae->ack, tp->snd_max)) {
                                /*
                                 * We just send an ack since the incoming
                                 * ack is beyond the largest seq we sent.
                                 */
                                if ((tp->t_flags & TF_ACKNOW) == 0) {
                                        ctf_ack_war_checks(tp);
                                        if (tp->t_flags && TF_ACKNOW)
                                                rack->r_wanted_output = 1;
                                }
                        } else {
                                nsegs++;
                                /* If the window changed setup to update */
                                if (tiwin != tp->snd_wnd) {
                                        win_upd_ack = ae->ack;
                                        win_seq = ae->seq;
                                        the_win = tiwin;
                                        rack_do_win_updates(tp, rack, the_win, win_seq, win_upd_ack, cts);
                                }
#ifdef TCP_ACCOUNTING
                                /* Account for the acks */
                                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                        tp->tcp_cnt_counters[CNT_OF_ACKS_IN] += (((ae->ack - high_seq) + segsiz - 1) / segsiz);
                                }
#endif
                                high_seq = ae->ack;
                                /* Setup our act_rcv_time */
                                if ((ae->flags & TSTMP_LRO) || (ae->flags & TSTMP_HDWR)) {
                                        ts.tv_sec = ae->timestamp / 1000000000;
                                        ts.tv_nsec = ae->timestamp % 1000000000;
                                        rack->r_ctl.act_rcv_time.tv_sec = ts.tv_sec;
                                        rack->r_ctl.act_rcv_time.tv_usec = ts.tv_nsec/1000;
                                } else {
                                        rack->r_ctl.act_rcv_time = *tv;
                                }
                                rack_process_to_cumack(tp, rack, ae->ack, cts, to,
                                                       tcp_tv_to_lusec(&rack->r_ctl.act_rcv_time));
#ifdef TCP_REQUEST_TRK
                                rack_req_check_for_comp(rack, high_seq);
#endif
                                if (rack->rc_dsack_round_seen) {
                                        /* Is the dsack round over? */
                                        if (SEQ_GEQ(ae->ack, rack->r_ctl.dsack_round_end)) {
                                                /* Yes it is */
                                                rack->rc_dsack_round_seen = 0;
                                                rack_log_dsack_event(rack, 3, __LINE__, 0, 0);
                                        }
                                }
                        }
                }
                /* And lets be sure to commit the rtt measurements for this ack */
                tcp_rack_xmit_timer_commit(rack, tp);
#ifdef TCP_ACCOUNTING
                rdstc = get_cyclecount();
                if (rdstc > ts_val) {
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_proc_time[ae->ack_val_set] += (rdstc - ts_val);
                                if (ae->ack_val_set == ACK_CUMACK)
                                        tp->tcp_proc_time[CYC_HANDLE_MAP] += (rdstc - ts_val);
                        }
                }
#endif
        }
#ifdef TCP_ACCOUNTING
        ts_val = get_cyclecount();
#endif
        /* Tend to any collapsed window */
        if (SEQ_GT(tp->snd_max, high_seq) && (tp->snd_wnd < (tp->snd_max - high_seq))) {
                /* The peer collapsed the window */
                rack_collapsed_window(rack, (tp->snd_max - high_seq), high_seq, __LINE__);
        } else if (rack->rc_has_collapsed)
                rack_un_collapse_window(rack, __LINE__);
        if ((rack->r_collapse_point_valid) &&
            (SEQ_GT(high_seq, rack->r_ctl.high_collapse_point)))
                rack->r_collapse_point_valid = 0;
        acked_amount = acked = (high_seq - tp->snd_una);
        if (acked) {
                /*
                 * The draft (v3) calls for us to use SEQ_GEQ, but that
                 * causes issues when we are just going app limited. Lets
                 * instead use SEQ_GT <or> where its equal but more data
                 * is outstanding.
                 *
                 * Also make sure we are on the last ack of a series. We
                 * have to have all the ack's processed in queue to know
                 * if there is something left outstanding.
                 *
                 */
                if (SEQ_GEQ(high_seq, rack->r_ctl.roundends) &&
                    (rack->rc_new_rnd_needed == 0) &&
                    (nxt_pkt == 0)) {
                        /*
                         * We have crossed into a new round with
                         * this th_ack value.
                         */
                        rack_new_round_setup(tp, rack, high_seq);
                }
                /*
                 * Clear the probe not answered flag
                 * since cum-ack moved forward.
                 */
                rack->probe_not_answered = 0;
                if (tp->t_flags & TF_NEEDSYN) {
                        /*
                         * T/TCP: Connection was half-synchronized, and our SYN has
                         * been ACK'd (so connection is now fully synchronized).  Go
                         * to non-starred state, increment snd_una for ACK of SYN,
                         * and check if we can do window scaling.
                         */
                        tp->t_flags &= ~TF_NEEDSYN;
                        tp->snd_una++;
                        acked_amount = acked = (high_seq - tp->snd_una);
                }
                if (acked > sbavail(&so->so_snd))
                        acked_amount = sbavail(&so->so_snd);
                if (IN_FASTRECOVERY(tp->t_flags) &&
                    (rack->rack_no_prr == 0))
                        rack_update_prr(tp, rack, acked_amount, high_seq);
                if (IN_RECOVERY(tp->t_flags)) {
                        if (SEQ_LT(high_seq, tp->snd_recover) &&
                            (SEQ_LT(high_seq, tp->snd_max))) {
                                tcp_rack_partialack(tp);
                        } else {
                                rack_post_recovery(tp, high_seq);
                                post_recovery = 1;
                        }
                }  else if ((rack->rto_from_rec == 1) &&
                            SEQ_GEQ(high_seq, tp->snd_recover)) {
                        /*
                         * We were in recovery, hit a rxt timeout
                         * and never re-entered recovery. The timeout(s)
                         * made up all the lost data. In such a case
                         * we need to clear the rto_from_rec flag.
                         */
                        rack->rto_from_rec = 0;
                }
                /* Handle the rack-log-ack part (sendmap) */
                if ((sbused(&so->so_snd) == 0) &&
                    (acked > acked_amount) &&
                    (tp->t_state >= TCPS_FIN_WAIT_1) &&
                    (tp->t_flags & TF_SENTFIN)) {
                        /*
                         * We must be sure our fin
                         * was sent and acked (we can be
                         * in FIN_WAIT_1 without having
                         * sent the fin).
                         */
                        ourfinisacked = 1;
                        /*
                         * Lets make sure snd_una is updated
                         * since most likely acked_amount = 0 (it
                         * should be).
                         */
                        tp->snd_una = high_seq;
                }
                /* Did we make a RTO error? */
                if ((tp->t_flags & TF_PREVVALID) &&
                    ((tp->t_flags & TF_RCVD_TSTMP) == 0)) {
                        tp->t_flags &= ~TF_PREVVALID;
                        if (tp->t_rxtshift == 1 &&
                            (int)(ticks - tp->t_badrxtwin) < 0)
                                rack_cong_signal(tp, CC_RTO_ERR, high_seq, __LINE__);
                }
                /* Handle the data in the socket buffer */
                KMOD_TCPSTAT_ADD(tcps_rcvackpack, 1);
                KMOD_TCPSTAT_ADD(tcps_rcvackbyte, acked);
                if (acked_amount > 0) {
                        uint32_t p_cwnd;
                        struct mbuf *mfree;

                        if (post_recovery) {
                                /*
                                 * Grab the segsiz, multiply by 2 and add the snd_cwnd
                                 * that is the max the CC should add if we are exiting
                                 * recovery and doing a late add.
                                 */
                                p_cwnd = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
                                p_cwnd <<= 1;
                                p_cwnd += tp->snd_cwnd;
                        }
                        rack_ack_received(tp, rack, high_seq, nsegs, CC_ACK, post_recovery);
                        if (post_recovery && (tp->snd_cwnd > p_cwnd)) {
                                /* Must be non-newreno (cubic) getting too ahead of itself */
                                tp->snd_cwnd = p_cwnd;
                        }
                        SOCK_SENDBUF_LOCK(so);
                        mfree = sbcut_locked(&so->so_snd, acked_amount);
                        tp->snd_una = high_seq;
                        /* Note we want to hold the sb lock through the sendmap adjust */
                        rack_adjust_sendmap_head(rack, &so->so_snd);
                        /* Wake up the socket if we have room to write more */
                        rack_log_wakeup(tp,rack, &so->so_snd, acked, 2);
                        sowwakeup_locked(so);
                        m_freem(mfree);
                }
                /* update progress */
                tp->t_acktime = ticks;
                rack_log_progress_event(rack, tp, tp->t_acktime,
                                        PROGRESS_UPDATE, __LINE__);
                /* Clear out shifts and such */
                tp->t_rxtshift = 0;
                RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                                   rack_rto_min, rack_rto_max, rack->r_ctl.timer_slop);
                rack->rc_tlp_in_progress = 0;
                rack->r_ctl.rc_tlp_cnt_out = 0;
                /* Send recover and snd_nxt must be dragged along */
                if (SEQ_GT(tp->snd_una, tp->snd_recover))
                        tp->snd_recover = tp->snd_una;
                if (SEQ_LT(tp->snd_nxt, tp->snd_max))
                        tp->snd_nxt = tp->snd_max;
                /*
                 * If the RXT timer is running we want to
                 * stop it, so we can restart a TLP (or new RXT).
                 */
                if (rack->r_ctl.rc_hpts_flags & PACE_TMR_RXT)
                        rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
                tp->snd_wl2 = high_seq;
                tp->t_dupacks = 0;
                if (under_pacing &&
                    (rack->use_fixed_rate == 0) &&
                    (rack->in_probe_rtt == 0) &&
                    rack->rc_gp_dyn_mul &&
                    rack->rc_always_pace) {
                        /* Check if we are dragging bottom */
                        rack_check_bottom_drag(tp, rack, so);
                }
                if (tp->snd_una == tp->snd_max) {
                        tp->t_flags &= ~TF_PREVVALID;
                        rack->r_ctl.retran_during_recovery = 0;
                        rack->rc_suspicious = 0;
                        rack->r_ctl.dsack_byte_cnt = 0;
                        rack->r_ctl.rc_went_idle_time = tcp_get_usecs(NULL);
                        if (rack->r_ctl.rc_went_idle_time == 0)
                                rack->r_ctl.rc_went_idle_time = 1;
                        rack_log_progress_event(rack, tp, 0, PROGRESS_CLEAR, __LINE__);
                        if (sbavail(&tptosocket(tp)->so_snd) == 0)
                                tp->t_acktime = 0;
                        /* Set so we might enter persists... */
                        rack->r_wanted_output = 1;
                        rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
                        sack_filter_clear(&rack->r_ctl.rack_sf, tp->snd_una);
                        if ((tp->t_state >= TCPS_FIN_WAIT_1) &&
                            (sbavail(&so->so_snd) == 0) &&
                            (tp->t_flags2 & TF2_DROP_AF_DATA)) {
                                /*
                                 * The socket was gone and the
                                 * peer sent data (not now in the past), time to
                                 * reset him.
                                 */
                                rack_timer_cancel(tp, rack, rack->r_ctl.rc_rcvtime, __LINE__);
                                /* tcp_close will kill the inp pre-log the Reset */
                                tcp_log_end_status(tp, TCP_EI_STATUS_SERVER_RST);
#ifdef TCP_ACCOUNTING
                                rdstc = get_cyclecount();
                                if (rdstc > ts_val) {
                                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                                tp->tcp_proc_time[ACK_CUMACK] += (rdstc - ts_val);
                                                tp->tcp_proc_time[CYC_HANDLE_ACK] += (rdstc - ts_val);
                                        }
                                }
#endif
                                m_freem(m);
                                tp = tcp_close(tp);
                                if (tp == NULL) {
#ifdef TCP_ACCOUNTING
                                        sched_unpin();
#endif
                                        return (1);
                                }
                                /*
                                 * We would normally do drop-with-reset which would
                                 * send back a reset. We can't since we don't have
                                 * all the needed bits. Instead lets arrange for
                                 * a call to tcp_output(). That way since we
                                 * are in the closed state we will generate a reset.
                                 *
                                 * Note if tcp_accounting is on we don't unpin since
                                 * we do that after the goto label.
                                 */
                                goto send_out_a_rst;
                        }
                        if ((sbused(&so->so_snd) == 0) &&
                            (tp->t_state >= TCPS_FIN_WAIT_1) &&
                            (tp->t_flags & TF_SENTFIN)) {
                                /*
                                 * If we can't receive any more data, then closing user can
                                 * proceed. Starting the timer is contrary to the
                                 * specification, but if we don't get a FIN we'll hang
                                 * forever.
                                 *
                                 */
                                if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                                        soisdisconnected(so);
                                        tcp_timer_activate(tp, TT_2MSL,
                                                           (tcp_fast_finwait2_recycle ?
                                                            tcp_finwait2_timeout :
                                                            TP_MAXIDLE(tp)));
                                }
                                if (ourfinisacked == 0) {
                                        /*
                                         * We don't change to fin-wait-2 if we have our fin acked
                                         * which means we are probably in TCPS_CLOSING.
                                         */
                                        tcp_state_change(tp, TCPS_FIN_WAIT_2);
                                }
                        }
                }
                /* Wake up the socket if we have room to write more */
                if (sbavail(&so->so_snd)) {
                        rack->r_wanted_output = 1;
                        if (ctf_progress_timeout_check(tp, true)) {
                                rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
                                                        tp, tick, PROGRESS_DROP, __LINE__);
                                /*
                                 * We cheat here and don't send a RST, we should send one
                                 * when the pacer drops the connection.
                                 */
#ifdef TCP_ACCOUNTING
                                rdstc = get_cyclecount();
                                if (rdstc > ts_val) {
                                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                                tp->tcp_proc_time[ACK_CUMACK] += (rdstc - ts_val);
                                                tp->tcp_proc_time[CYC_HANDLE_ACK] += (rdstc - ts_val);
                                        }
                                }
                                sched_unpin();
#endif
                                (void)tcp_drop(tp, ETIMEDOUT);
                                m_freem(m);
                                return (1);
                        }
                }
                if (ourfinisacked) {
                        switch(tp->t_state) {
                        case TCPS_CLOSING:
#ifdef TCP_ACCOUNTING
                                rdstc = get_cyclecount();
                                if (rdstc > ts_val) {
                                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                                tp->tcp_proc_time[ACK_CUMACK] += (rdstc - ts_val);
                                                tp->tcp_proc_time[CYC_HANDLE_ACK] += (rdstc - ts_val);
                                        }
                                }
                                sched_unpin();
#endif
                                tcp_twstart(tp);
                                m_freem(m);
                                return (1);
                                break;
                        case TCPS_LAST_ACK:
#ifdef TCP_ACCOUNTING
                                rdstc = get_cyclecount();
                                if (rdstc > ts_val) {
                                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                                tp->tcp_proc_time[ACK_CUMACK] += (rdstc - ts_val);
                                                tp->tcp_proc_time[CYC_HANDLE_ACK] += (rdstc - ts_val);
                                        }
                                }
                                sched_unpin();
#endif
                                tp = tcp_close(tp);
                                ctf_do_drop(m, tp);
                                return (1);
                                break;
                        case TCPS_FIN_WAIT_1:
#ifdef TCP_ACCOUNTING
                                rdstc = get_cyclecount();
                                if (rdstc > ts_val) {
                                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                                tp->tcp_proc_time[ACK_CUMACK] += (rdstc - ts_val);
                                                tp->tcp_proc_time[CYC_HANDLE_ACK] += (rdstc - ts_val);
                                        }
                                }
#endif
                                if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
                                        soisdisconnected(so);
                                        tcp_timer_activate(tp, TT_2MSL,
                                                           (tcp_fast_finwait2_recycle ?
                                                            tcp_finwait2_timeout :
                                                            TP_MAXIDLE(tp)));
                                }
                                tcp_state_change(tp, TCPS_FIN_WAIT_2);
                                break;
                        default:
                                break;
                        }
                }
                if (rack->r_fast_output) {
                        /*
                         * We re doing fast output.. can we expand that?
                         */
                        rack_gain_for_fastoutput(rack, tp, so, acked_amount);
                }
#ifdef TCP_ACCOUNTING
                rdstc = get_cyclecount();
                if (rdstc > ts_val) {
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_proc_time[ACK_CUMACK] += (rdstc - ts_val);
                                tp->tcp_proc_time[CYC_HANDLE_ACK] += (rdstc - ts_val);
                        }
                }

        } else if (win_up_req) {
                rdstc = get_cyclecount();
                if (rdstc > ts_val) {
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_proc_time[ACK_RWND] += (rdstc - ts_val);
                        }
                }
#endif
        }
        /* Now is there a next packet, if so we are done */
        m_freem(m);
        did_out = 0;
        if (nxt_pkt) {
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                rack_log_doseg_done(rack, cts, nxt_pkt, did_out, 5, nsegs);
                return (0);
        }
        rack_handle_might_revert(tp, rack);
        ctf_calc_rwin(so, tp);
        if ((rack->r_wanted_output != 0) ||
            (rack->r_fast_output != 0) ||
            (tp->t_flags & TF_ACKNOW )) {
        send_out_a_rst:
                if (tcp_output(tp) < 0) {
#ifdef TCP_ACCOUNTING
                        sched_unpin();
#endif
                        return (1);
                }
                did_out = 1;
        }
        if (tp->t_flags2 & TF2_HPTS_CALLS)
                tp->t_flags2 &= ~TF2_HPTS_CALLS;
        rack_free_trim(rack);
#ifdef TCP_ACCOUNTING
        sched_unpin();
#endif
        rack_timer_audit(tp, rack, &so->so_snd);
        rack_log_doseg_done(rack, cts, nxt_pkt, did_out, 6, nsegs);
        return (0);
}

#define TCP_LRO_TS_OPTION \
    ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | \
          (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)

static int
rack_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
    int32_t drop_hdrlen, int32_t tlen, uint8_t iptos, int32_t nxt_pkt,
    struct timeval *tv)
{
        struct inpcb *inp = tptoinpcb(tp);
        struct socket *so = tptosocket(tp);
#ifdef TCP_ACCOUNTING
        uint64_t ts_val;
#endif
        int32_t thflags, retval, did_out = 0;
        int32_t way_out = 0;
        /*
         * cts - is the current time from tv (caller gets ts) in microseconds.
         * ms_cts - is the current time from tv in milliseconds.
         * us_cts - is the time that LRO or hardware actually got the packet in microseconds.
         */
        uint32_t cts, us_cts, ms_cts;
        uint32_t tiwin;
        struct timespec ts;
        struct tcpopt to;
        struct tcp_rack *rack;
        struct rack_sendmap *rsm;
        int32_t prev_state = 0;
        int no_output = 0;
        int time_remaining = 0;
#ifdef TCP_ACCOUNTING
        int ack_val_set = 0xf;
#endif
        int nsegs;

        NET_EPOCH_ASSERT();
        INP_WLOCK_ASSERT(inp);

        /*
         * tv passed from common code is from either M_TSTMP_LRO or
         * tcp_get_usecs() if no LRO m_pkthdr timestamp is present.
         */
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->rack_deferred_inited == 0) {
                /*
                 * If we are the connecting socket we will
                 * hit rack_init() when no sequence numbers
                 * are setup. This makes it so we must defer
                 * some initialization. Call that now.
                 */
                rack_deferred_init(tp, rack);
        }
        /*
         * Check to see if we need to skip any output plans. This
         * can happen in the non-LRO path where we are pacing and
         * must process the ack coming in but need to defer sending
         * anything becase a pacing timer is running.
         */
        us_cts = tcp_tv_to_usec(tv);
        if (m->m_flags & M_ACKCMP) {
                /*
                 * All compressed ack's are ack's by definition so
                 * remove any ack required flag and then do the processing.
                 */
                rack->rc_ack_required = 0;
                return (rack_do_compressed_ack_processing(tp, so, m, nxt_pkt, tv));
        }
        thflags = tcp_get_flags(th);
        if ((rack->rc_always_pace == 1) &&
            (rack->rc_ack_can_sendout_data == 0) &&
            (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) &&
            (TSTMP_LT(us_cts, rack->r_ctl.rc_last_output_to))) {
                /*
                 * Ok conditions are right for queuing the packets
                 * but we do have to check the flags in the inp, it
                 * could be, if a sack is present, we want to be awoken and
                 * so should process the packets.
                 */
                time_remaining = rack->r_ctl.rc_last_output_to - us_cts;
                if (rack->rc_tp->t_flags2 & TF2_DONT_SACK_QUEUE) {
                        no_output = 1;
                } else {
                        /*
                         * If there is no options, or just a
                         * timestamp option, we will want to queue
                         * the packets. This is the same that LRO does
                         * and will need to change with accurate ECN.
                         */
                        uint32_t *ts_ptr;
                        int optlen;

                        optlen = (th->th_off << 2) - sizeof(struct tcphdr);
                        ts_ptr = (uint32_t *)(th + 1);
                        if ((optlen == 0) ||
                            ((optlen == TCPOLEN_TSTAMP_APPA) &&
                             (*ts_ptr == TCP_LRO_TS_OPTION)))
                                no_output = 1;
                }
                if ((no_output == 1) && (time_remaining < tcp_min_hptsi_time)) {
                        /*
                         * It is unrealistic to think we can pace in less than
                         * the minimum granularity of the pacer (def:250usec). So
                         * if we have less than that time remaining we should go
                         * ahead and allow output to be "early". We will attempt to
                         * make up for it in any pacing time we try to apply on
                         * the outbound packet.
                         */
                        no_output = 0;
                }
        }
        /*
         * If there is a RST or FIN lets dump out the bw
         * with a FIN the connection may go on but we
         * may not.
         */
        if ((thflags & TH_FIN) || (thflags & TH_RST))
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.gp_bw,
                                           0,
                                           0,
                                           rack_get_gp_est(rack), /* delRate */
                                           rack_get_lt_bw(rack), /* rttProp */
                                           20, __LINE__, NULL, 0);
        if (m->m_flags & M_ACKCMP) {
                panic("Impossible reach m has ackcmp? m:%p tp:%p", m, tp);
        }
        cts = tcp_tv_to_usec(tv);
        ms_cts =  tcp_tv_to_msec(tv);
        nsegs = m->m_pkthdr.lro_nsegs;
        counter_u64_add(rack_proc_non_comp_ack, 1);
#ifdef TCP_ACCOUNTING
        sched_pin();
        if (thflags & TH_ACK)
                ts_val = get_cyclecount();
#endif
        if ((m->m_flags & M_TSTMP) ||
            (m->m_flags & M_TSTMP_LRO)) {
                mbuf_tstmp2timespec(m, &ts);
                rack->r_ctl.act_rcv_time.tv_sec = ts.tv_sec;
                rack->r_ctl.act_rcv_time.tv_usec = ts.tv_nsec/1000;
        } else
                rack->r_ctl.act_rcv_time = *tv;
        kern_prefetch(rack, &prev_state);
        prev_state = 0;
        /*
         * Unscale the window into a 32-bit value. For the SYN_SENT state
         * the scale is zero.
         */
        tiwin = th->th_win << tp->snd_scale;
#ifdef TCP_ACCOUNTING
        if (thflags & TH_ACK) {
                /*
                 * We have a tradeoff here. We can either do what we are
                 * doing i.e. pinning to this CPU and then doing the accounting
                 * <or> we could do a critical enter, setup the rdtsc and cpu
                 * as in below, and then validate we are on the same CPU on
                 * exit. I have choosen to not do the critical enter since
                 * that often will gain you a context switch, and instead lock
                 * us (line above this if) to the same CPU with sched_pin(). This
                 * means we may be context switched out for a higher priority
                 * interupt but we won't be moved to another CPU.
                 *
                 * If this occurs (which it won't very often since we most likely
                 * are running this code in interupt context and only a higher
                 * priority will bump us ... clock?) we will falsely add in
                 * to the time the interupt processing time plus the ack processing
                 * time. This is ok since its a rare event.
                 */
                ack_val_set = tcp_do_ack_accounting(tp, th, &to, tiwin,
                                                    ctf_fixed_maxseg(tp));
        }
#endif
        /*
         * Parse options on any incoming segment.
         */
        memset(&to, 0, sizeof(to));
        tcp_dooptions(&to, (u_char *)(th + 1),
            (th->th_off << 2) - sizeof(struct tcphdr),
            (thflags & TH_SYN) ? TO_SYN : 0);
        KASSERT(tp->t_state > TCPS_LISTEN, ("%s: TCPS_LISTEN",
            __func__));
        KASSERT(tp->t_state != TCPS_TIME_WAIT, ("%s: TCPS_TIME_WAIT",
            __func__));
        if (tp->t_flags2 & TF2_PROC_SACK_PROHIBIT) {
                /*
                 * We don't look at sack's from the
                 * peer because the MSS is too small which
                 * can subject us to an attack.
                 */
                to.to_flags &= ~TOF_SACK;
        }
        if ((tp->t_state >= TCPS_FIN_WAIT_1) &&
            (tp->t_flags & TF_GPUTINPROG)) {
                /*
                 * We have a goodput in progress
                 * and we have entered a late state.
                 * Do we have enough data in the sb
                 * to handle the GPUT request?
                 */
                uint32_t bytes;

                bytes = tp->gput_ack - tp->gput_seq;
                if (SEQ_GT(tp->gput_seq, tp->snd_una))
                        bytes += tp->gput_seq - tp->snd_una;
                if (bytes > sbavail(&tptosocket(tp)->so_snd)) {
                        /*
                         * There are not enough bytes in the socket
                         * buffer that have been sent to cover this
                         * measurement. Cancel it.
                         */
                        rack_log_pacing_delay_calc(rack, (tp->gput_ack - tp->gput_seq) /*flex2*/,
                                                   rack->r_ctl.rc_gp_srtt /*flex1*/,
                                                   tp->gput_seq,
                                                   0, 0, 18, __LINE__, NULL, 0);
                        tp->t_flags &= ~TF_GPUTINPROG;
                }
        }
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval ltv;
#ifdef TCP_REQUEST_TRK
                struct tcp_sendfile_track *tcp_req;

                if (SEQ_GT(th->th_ack, tp->snd_una)) {
                        tcp_req = tcp_req_find_req_for_seq(tp, (th->th_ack-1));
                } else {
                        tcp_req = tcp_req_find_req_for_seq(tp, th->th_ack);
                }
#endif
                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                if (rack->rack_no_prr == 0)
                        log.u_bbr.flex1 = rack->r_ctl.rc_prr_sndcnt;
                else
                        log.u_bbr.flex1 = 0;
                log.u_bbr.use_lt_bw = rack->r_ent_rec_ns;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->r_might_revert;
                log.u_bbr.flex2 = rack->r_ctl.rc_num_maps_alloced;
                log.u_bbr.bbr_state = rack->rc_free_cnt;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.pkts_out = rack->rc_tp->t_maxseg;
                log.u_bbr.flex3 = m->m_flags;
                log.u_bbr.flex4 = rack->r_ctl.rc_hpts_flags;
                log.u_bbr.lost = thflags;
                log.u_bbr.pacing_gain = 0x1;
#ifdef TCP_ACCOUNTING
                log.u_bbr.cwnd_gain = ack_val_set;
#endif
                log.u_bbr.flex7 = 2;
                if (m->m_flags & M_TSTMP) {
                        /* Record the hardware timestamp if present */
                        mbuf_tstmp2timespec(m, &ts);
                        ltv.tv_sec = ts.tv_sec;
                        ltv.tv_usec = ts.tv_nsec / 1000;
                        log.u_bbr.lt_epoch = tcp_tv_to_usec(&ltv);
                } else if (m->m_flags & M_TSTMP_LRO) {
                        /* Record the LRO the arrival timestamp */
                        mbuf_tstmp2timespec(m, &ts);
                        ltv.tv_sec = ts.tv_sec;
                        ltv.tv_usec = ts.tv_nsec / 1000;
                        log.u_bbr.flex5 = tcp_tv_to_usec(&ltv);
                }
                log.u_bbr.timeStamp = tcp_get_usecs(&ltv);
                /* Log the rcv time */
                log.u_bbr.delRate = m->m_pkthdr.rcv_tstmp;
#ifdef TCP_REQUEST_TRK
                log.u_bbr.applimited = tp->t_tcpreq_closed;
                log.u_bbr.applimited <<= 8;
                log.u_bbr.applimited |= tp->t_tcpreq_open;
                log.u_bbr.applimited <<= 8;
                log.u_bbr.applimited |= tp->t_tcpreq_req;
                if (tcp_req) {
                        /* Copy out any client req info */
                        /* seconds */
                        log.u_bbr.pkt_epoch = (tcp_req->localtime / HPTS_USEC_IN_SEC);
                        /* useconds */
                        log.u_bbr.delivered = (tcp_req->localtime % HPTS_USEC_IN_SEC);
                        log.u_bbr.rttProp = tcp_req->timestamp;
                        log.u_bbr.cur_del_rate = tcp_req->start;
                        if (tcp_req->flags & TCP_TRK_TRACK_FLG_OPEN) {
                                log.u_bbr.flex8 |= 1;
                        } else {
                                log.u_bbr.flex8 |= 2;
                                log.u_bbr.bw_inuse = tcp_req->end;
                        }
                        log.u_bbr.flex6 = tcp_req->start_seq;
                        if (tcp_req->flags & TCP_TRK_TRACK_FLG_COMP) {
                                log.u_bbr.flex8 |= 4;
                                log.u_bbr.epoch = tcp_req->end_seq;
                        }
                }
#endif
                TCP_LOG_EVENTP(tp, th, &so->so_rcv, &so->so_snd, TCP_LOG_IN, 0,
                    tlen, &log, true, &ltv);
        }
        /* Remove ack required flag if set, we have one  */
        if (thflags & TH_ACK)
                rack->rc_ack_required = 0;
        rack_log_type_bbrsnd(rack, 0, 0, cts, tv, __LINE__);
        if ((thflags & TH_SYN) && (thflags & TH_FIN) && V_drop_synfin) {
                way_out = 4;
                retval = 0;
                m_freem(m);
                goto done_with_input;
        }
        /*
         * If a segment with the ACK-bit set arrives in the SYN-SENT state
         * check SEQ.ACK first as described on page 66 of RFC 793, section 3.9.
         */
        if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) &&
            (SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) {
                tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
                ctf_do_dropwithreset(m, tp, th, tlen);
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                return (1);
        }
        /*
         * If timestamps were negotiated during SYN/ACK and a
         * segment without a timestamp is received, silently drop
         * the segment, unless it is a RST segment or missing timestamps are
         * tolerated.
         * See section 3.2 of RFC 7323.
         */
        if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS) &&
            ((thflags & TH_RST) == 0) && (V_tcp_tolerate_missing_ts == 0)) {
                way_out = 5;
                retval = 0;
                m_freem(m);
                goto done_with_input;
        }
        /*
         * Segment received on connection. Reset idle time and keep-alive
         * timer. XXX: This should be done after segment validation to
         * ignore broken/spoofed segs.
         */
        if  (tp->t_idle_reduce &&
             (tp->snd_max == tp->snd_una) &&
             (TICKS_2_USEC(ticks - tp->t_rcvtime) >= tp->t_rxtcur)) {
                counter_u64_add(rack_input_idle_reduces, 1);
                rack_cc_after_idle(rack, tp);
        }
        tp->t_rcvtime = ticks;
#ifdef STATS
        stats_voi_update_abs_ulong(tp->t_stats, VOI_TCP_FRWIN, tiwin);
#endif
        if (tiwin > rack->r_ctl.rc_high_rwnd)
                rack->r_ctl.rc_high_rwnd = tiwin;
        /*
         * TCP ECN processing. XXXJTL: If we ever use ECN, we need to move
         * this to occur after we've validated the segment.
         */
        if (tcp_ecn_input_segment(tp, thflags, tlen,
            tcp_packets_this_ack(tp, th->th_ack),
            iptos))
                rack_cong_signal(tp, CC_ECN, th->th_ack, __LINE__);
        if (tp->t_flags & TF_ACKNOW)
                rack->r_wanted_output = 1;
        /*
         * If echoed timestamp is later than the current time, fall back to
         * non RFC1323 RTT calculation.  Normalize timestamp if syncookies
         * were used when this connection was established.
         */
        if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) {
                to.to_tsecr -= tp->ts_offset;
                if (TSTMP_GT(to.to_tsecr, ms_cts))
                        to.to_tsecr = 0;
        }
        if ((rack->r_rcvpath_rtt_up == 1) &&
            (to.to_flags & TOF_TS) &&
            (TSTMP_GEQ(to.to_tsecr, rack->r_ctl.last_rcv_tstmp_for_rtt))) {
                uint32_t rtt = 0;

                /*
                 * We are receiving only and thus not sending
                 * data to do an RTT. We set a flag when we first
                 * sent this TS to the peer. We now have it back
                 * and have an RTT to share. We log it as a conf
                 * 4, we are not so sure about it.. since we
                 * may have lost an ack.
                 */
                if (TSTMP_GT(cts, rack->r_ctl.last_time_of_arm_rcv))
                    rtt = (cts - rack->r_ctl.last_time_of_arm_rcv);
                rack->r_rcvpath_rtt_up = 0;
                /* Submit and commit the timer */
                if (rtt > 0) {
                        tcp_rack_xmit_timer(rack, rtt, 0, rtt, 4, NULL, 1);
                        tcp_rack_xmit_timer_commit(rack, tp);
                }
        }
        /*
         * If its the first time in we need to take care of options and
         * verify we can do SACK for rack!
         */
        if (rack->r_state == 0) {
                /* Should be init'd by rack_init() */
                KASSERT(rack->rc_inp != NULL,
                    ("%s: rack->rc_inp unexpectedly NULL", __func__));
                if (rack->rc_inp == NULL) {
                        rack->rc_inp = inp;
                }

                /*
                 * Process options only when we get SYN/ACK back. The SYN
                 * case for incoming connections is handled in tcp_syncache.
                 * According to RFC1323 the window field in a SYN (i.e., a
                 * <SYN> or <SYN,ACK>) segment itself is never scaled. XXX
                 * this is traditional behavior, may need to be cleaned up.
                 */
                if (tp->t_state == TCPS_SYN_SENT && (thflags & TH_SYN)) {
                        /* Handle parallel SYN for ECN */
                        tcp_ecn_input_parallel_syn(tp, thflags, iptos);
                        if ((to.to_flags & TOF_SCALE) &&
                            (tp->t_flags & TF_REQ_SCALE)) {
                                tp->t_flags |= TF_RCVD_SCALE;
                                tp->snd_scale = to.to_wscale;
                        } else
                                tp->t_flags &= ~TF_REQ_SCALE;
                        /*
                         * Initial send window.  It will be updated with the
                         * next incoming segment to the scaled value.
                         */
                        tp->snd_wnd = th->th_win;
                        rack_validate_fo_sendwin_up(tp, rack);
                        if ((to.to_flags & TOF_TS) &&
                            (tp->t_flags & TF_REQ_TSTMP)) {
                                tp->t_flags |= TF_RCVD_TSTMP;
                                tp->ts_recent = to.to_tsval;
                                tp->ts_recent_age = cts;
                        } else
                                tp->t_flags &= ~TF_REQ_TSTMP;
                        if (to.to_flags & TOF_MSS) {
                                tcp_mss(tp, to.to_mss);
                        }
                        if ((tp->t_flags & TF_SACK_PERMIT) &&
                            (to.to_flags & TOF_SACKPERM) == 0)
                                tp->t_flags &= ~TF_SACK_PERMIT;
                        if (tp->t_flags & TF_FASTOPEN) {
                                if (to.to_flags & TOF_FASTOPEN) {
                                        uint16_t mss;

                                        if (to.to_flags & TOF_MSS)
                                                mss = to.to_mss;
                                        else
                                                if ((inp->inp_vflag & INP_IPV6) != 0)
                                                        mss = TCP6_MSS;
                                                else
                                                        mss = TCP_MSS;
                                        tcp_fastopen_update_cache(tp, mss,
                                            to.to_tfo_len, to.to_tfo_cookie);
                                } else
                                        tcp_fastopen_disable_path(tp);
                        }
                }
                /*
                 * At this point we are at the initial call. Here we decide
                 * if we are doing RACK or not. We do this by seeing if
                 * TF_SACK_PERMIT is set and the sack-not-required is clear.
                 * The code now does do dup-ack counting so if you don't
                 * switch back you won't get rack & TLP, but you will still
                 * get this stack.
                 */

                if ((rack_sack_not_required == 0) &&
                    ((tp->t_flags & TF_SACK_PERMIT) == 0)) {
                        tcp_switch_back_to_default(tp);
                        (*tp->t_fb->tfb_tcp_do_segment)(tp, m, th, drop_hdrlen,
                            tlen, iptos);
#ifdef TCP_ACCOUNTING
                        sched_unpin();
#endif
                        return (1);
                }
                tcp_set_hpts(tp);
                sack_filter_clear(&rack->r_ctl.rack_sf, th->th_ack);
        }
        if (thflags & TH_FIN)
                tcp_log_end_status(tp, TCP_EI_STATUS_CLIENT_FIN);
        us_cts = tcp_tv_to_usec(&rack->r_ctl.act_rcv_time);
        if ((rack->rc_gp_dyn_mul) &&
            (rack->use_fixed_rate == 0) &&
            (rack->rc_always_pace)) {
                /* Check in on probertt */
                rack_check_probe_rtt(rack, cts);
        }
        rack_clear_rate_sample(rack);
        if ((rack->forced_ack) &&
            ((tcp_get_flags(th) & TH_RST) == 0)) {
                rack_handle_probe_response(rack, tiwin, us_cts);
        }
        /*
         * This is the one exception case where we set the rack state
         * always. All other times (timers etc) we must have a rack-state
         * set (so we assure we have done the checks above for SACK).
         */
        rack->r_ctl.rc_rcvtime = cts;
        if (rack->r_state != tp->t_state)
                rack_set_state(tp, rack);
        if (SEQ_GT(th->th_ack, tp->snd_una) &&
            (rsm = tqhash_min(rack->r_ctl.tqh)) != NULL)
                kern_prefetch(rsm, &prev_state);
        prev_state = rack->r_state;
        if ((thflags & TH_RST) &&
            ((SEQ_GEQ(th->th_seq, tp->last_ack_sent) &&
              SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) ||
             (tp->rcv_wnd == 0 && tp->last_ack_sent == th->th_seq))) {
                /* The connection will be killed by a reset check the tracepoint */
                tcp_trace_point(rack->rc_tp, TCP_TP_RESET_RCV);
        }
        retval = (*rack->r_substate) (m, th, so,
            tp, &to, drop_hdrlen,
            tlen, tiwin, thflags, nxt_pkt, iptos);
        if (retval == 0) {
                /*
                 * If retval is 1 the tcb is unlocked and most likely the tp
                 * is gone.
                 */
                INP_WLOCK_ASSERT(inp);
                if ((rack->rc_gp_dyn_mul) &&
                    (rack->rc_always_pace) &&
                    (rack->use_fixed_rate == 0) &&
                    rack->in_probe_rtt &&
                    (rack->r_ctl.rc_time_probertt_starts == 0)) {
                        /*
                         * If we are going for target, lets recheck before
                         * we output.
                         */
                        rack_check_probe_rtt(rack, cts);
                }
                if (rack->set_pacing_done_a_iw == 0) {
                        /* How much has been acked? */
                        if ((tp->snd_una - tp->iss) > (ctf_fixed_maxseg(tp) * 10)) {
                                /* We have enough to set in the pacing segment size */
                                rack->set_pacing_done_a_iw = 1;
                                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                        }
                }
                tcp_rack_xmit_timer_commit(rack, tp);
#ifdef TCP_ACCOUNTING
                /*
                 * If we set the ack_val_se to what ack processing we are doing
                 * we also want to track how many cycles we burned. Note
                 * the bits after tcp_output we let be "free". This is because
                 * we are also tracking the tcp_output times as well. Note the
                 * use of 0xf here since we only have 11 counter (0 - 0xa) and
                 * 0xf cannot be returned and is what we initialize it too to
                 * indicate we are not doing the tabulations.
                 */
                if (ack_val_set != 0xf) {
                        uint64_t crtsc;

                        crtsc = get_cyclecount();
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_proc_time[ack_val_set] += (crtsc - ts_val);
                        }
                }
#endif
                if ((nxt_pkt == 0) && (no_output == 0)) {
                        if ((rack->r_wanted_output != 0) ||
                            (tp->t_flags & TF_ACKNOW) ||
                            (rack->r_fast_output != 0)) {

do_output_now:
                                if (tcp_output(tp) < 0) {
#ifdef TCP_ACCOUNTING
                                        sched_unpin();
#endif
                                        return (1);
                                }
                                did_out = 1;
                        }
                        rack_start_hpts_timer(rack, tp, cts, 0, 0, 0);
                        rack_free_trim(rack);
                } else if ((nxt_pkt == 0) && (tp->t_flags & TF_ACKNOW)) {
                        goto do_output_now;
                } else if ((no_output == 1) &&
                           (nxt_pkt == 0) &&
                           (tcp_in_hpts(rack->rc_tp) == 0)) {
                        /*
                         * We are not in hpts and we had a pacing timer up. Use
                         * the remaining time (time_remaining) to restart the timer.
                         */
                        KASSERT ((time_remaining != 0), ("slot remaining is zero for rack:%p tp:%p", rack, tp));
                        rack_start_hpts_timer(rack, tp, cts, time_remaining, 0, 0);
                        rack_free_trim(rack);
                }
                /* Clear the flag, it may have been cleared by output but we may not have  */
                if ((nxt_pkt == 0) && (tp->t_flags2 & TF2_HPTS_CALLS))
                        tp->t_flags2 &= ~TF2_HPTS_CALLS;
                /*
                 * The draft (v3) calls for us to use SEQ_GEQ, but that
                 * causes issues when we are just going app limited. Lets
                 * instead use SEQ_GT <or> where its equal but more data
                 * is outstanding.
                 *
                 * Also make sure we are on the last ack of a series. We
                 * have to have all the ack's processed in queue to know
                 * if there is something left outstanding.
                 */
                if (SEQ_GEQ(tp->snd_una, rack->r_ctl.roundends) &&
                    (rack->rc_new_rnd_needed == 0) &&
                    (nxt_pkt == 0)) {
                        /*
                         * We have crossed into a new round with
                         * the new snd_unae.
                         */
                        rack_new_round_setup(tp, rack, tp->snd_una);
                }
                if ((nxt_pkt == 0) &&
                    ((rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK) == 0) &&
                    (SEQ_GT(tp->snd_max, tp->snd_una) ||
                     (tp->t_flags & TF_DELACK) ||
                     ((V_tcp_always_keepalive || rack->rc_inp->inp_socket->so_options & SO_KEEPALIVE) &&
                      (tp->t_state <= TCPS_CLOSING)))) {
                        /* We could not send (probably in the hpts but stopped the timer earlier)? */
                        if ((tp->snd_max == tp->snd_una) &&
                            ((tp->t_flags & TF_DELACK) == 0) &&
                            (tcp_in_hpts(rack->rc_tp)) &&
                            (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT)) {
                                /* keep alive not needed if we are hptsi output yet */
                                ;
                        } else {
                                int late = 0;
                                if (tcp_in_hpts(tp)) {
                                        if (rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) {
                                                us_cts = tcp_get_usecs(NULL);
                                                if (TSTMP_GT(rack->r_ctl.rc_last_output_to, us_cts)) {
                                                        rack->r_early = 1;
                                                        rack->r_ctl.rc_agg_early += (rack->r_ctl.rc_last_output_to - us_cts);
                                                } else
                                                        late = 1;
                                                rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
                                        }
                                        tcp_hpts_remove(tp);
                                }
                                if (late && (did_out == 0)) {
                                        /*
                                         * We are late in the sending
                                         * and we did not call the output
                                         * (this probably should not happen).
                                         */
                                        goto do_output_now;
                                }
                                rack_start_hpts_timer(rack, tp, tcp_get_usecs(NULL), 0, 0, 0);
                        }
                        way_out = 1;
                } else if (nxt_pkt == 0) {
                        /* Do we have the correct timer running? */
                        rack_timer_audit(tp, rack, &so->so_snd);
                        way_out = 2;
                }
        done_with_input:
                rack_log_doseg_done(rack, cts, nxt_pkt, did_out, way_out, max(1, nsegs));
                if (did_out)
                        rack->r_wanted_output = 0;
        }

#ifdef TCP_ACCOUNTING
        sched_unpin();
#endif
        return (retval);
}

static void
rack_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
    int32_t drop_hdrlen, int32_t tlen, uint8_t iptos)
{
        struct timeval tv;

        /* First lets see if we have old packets */
        if (!STAILQ_EMPTY(&tp->t_inqueue)) {
                if (ctf_do_queued_segments(tp, 1)) {
                        m_freem(m);
                        return;
                }
        }
        if (m->m_flags & M_TSTMP_LRO) {
                mbuf_tstmp2timeval(m, &tv);
        } else {
                /* Should not be should we kassert instead? */
                tcp_get_usecs(&tv);
        }
        if (rack_do_segment_nounlock(tp, m, th, drop_hdrlen, tlen, iptos, 0,
            &tv) == 0) {
                INP_WUNLOCK(tptoinpcb(tp));
        }
}

struct rack_sendmap *
tcp_rack_output(struct tcpcb *tp, struct tcp_rack *rack, uint32_t tsused)
{
        struct rack_sendmap *rsm = NULL;
        int32_t idx;
        uint32_t srtt = 0, thresh = 0, ts_low = 0;

        /* Return the next guy to be re-transmitted */
        if (tqhash_empty(rack->r_ctl.tqh)) {
                return (NULL);
        }
        if (tp->t_flags & TF_SENTFIN) {
                /* retran the end FIN? */
                return (NULL);
        }
        /* ok lets look at this one */
        rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
        if (rack->r_must_retran && rsm && (rsm->r_flags & RACK_MUST_RXT)) {
                return (rsm);
        }
        if (rsm && ((rsm->r_flags & RACK_ACKED) == 0)) {
                goto check_it;
        }
        rsm = rack_find_lowest_rsm(rack);
        if (rsm == NULL) {
                return (NULL);
        }
check_it:
        if (((rack->rc_tp->t_flags & TF_SACK_PERMIT) == 0) &&
            (rsm->r_dupack >= DUP_ACK_THRESHOLD)) {
                /*
                 * No sack so we automatically do the 3 strikes and
                 * retransmit (no rack timer would be started).
                 */
                return (rsm);
        }
        if (rsm->r_flags & RACK_ACKED) {
                return (NULL);
        }
        if (((rsm->r_flags & RACK_SACK_PASSED) == 0) &&
            (rsm->r_dupack < DUP_ACK_THRESHOLD)) {
                /* Its not yet ready */
                return (NULL);
        }
        srtt = rack_grab_rtt(tp, rack);
        idx = rsm->r_rtr_cnt - 1;
        ts_low = (uint32_t)rsm->r_tim_lastsent[idx];
        thresh = rack_calc_thresh_rack(rack, srtt, tsused, __LINE__, 1);
        if ((tsused == ts_low) ||
            (TSTMP_LT(tsused, ts_low))) {
                /* No time since sending */
                return (NULL);
        }
        if ((tsused - ts_low) < thresh) {
                /* It has not been long enough yet */
                return (NULL);
        }
        if ((rsm->r_dupack >= DUP_ACK_THRESHOLD) ||
            ((rsm->r_flags & RACK_SACK_PASSED))) {
                /*
                 * We have passed the dup-ack threshold <or>
                 * a SACK has indicated this is missing.
                 * Note that if you are a declared attacker
                 * it is only the dup-ack threshold that
                 * will cause retransmits.
                 */
                /* log retransmit reason */
                rack_log_retran_reason(rack, rsm, (tsused - ts_low), thresh, 1);
                rack->r_fast_output = 0;
                return (rsm);
        }
        return (NULL);
}

static void
rack_log_pacing_delay_calc (struct tcp_rack *rack, uint32_t len, uint32_t pacing_delay,
                           uint64_t bw_est, uint64_t bw, uint64_t len_time, int method,
                           int line, struct rack_sendmap *rsm, uint8_t quality)
{
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                if (rack_verbose_logging == 0) {
                        /*
                         * We are not verbose screen out all but
                         * ones we always want.
                         */
                        if ((method != 2) &&
                            (method != 3) &&
                            (method != 7) &&
                            (method != 89) &&
                            (method != 14) &&
                            (method != 20)) {
                                return;
                        }
                }
                memset(&log, 0, sizeof(log));
                log.u_bbr.flex1 = pacing_delay;
                log.u_bbr.flex2 = len;
                log.u_bbr.flex3 = rack->r_ctl.rc_pace_min_segs;
                log.u_bbr.flex4 = rack->r_ctl.rc_pace_max_segs;
                log.u_bbr.flex5 = rack->r_ctl.rack_per_of_gp_ss;
                log.u_bbr.flex6 = rack->r_ctl.rack_per_of_gp_ca;
                log.u_bbr.use_lt_bw = rack->rc_ack_can_sendout_data;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->r_late;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->r_early;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->app_limited_needs_set;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->rc_gp_filled;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->measure_saw_probe_rtt;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->in_probe_rtt;
                log.u_bbr.use_lt_bw <<= 1;
                log.u_bbr.use_lt_bw |= rack->gp_ready;
                log.u_bbr.pkt_epoch = line;
                log.u_bbr.epoch = rack->r_ctl.rc_agg_delayed;
                log.u_bbr.lt_epoch = rack->r_ctl.rc_agg_early;
                log.u_bbr.applimited = rack->r_ctl.rack_per_of_gp_rec;
                log.u_bbr.bw_inuse = bw_est;
                log.u_bbr.delRate = bw;
                if (rack->r_ctl.gp_bw == 0)
                        log.u_bbr.cur_del_rate = 0;
                else
                        log.u_bbr.cur_del_rate = rack_get_bw(rack);
                log.u_bbr.rttProp = len_time;
                log.u_bbr.pkts_out = rack->r_ctl.rc_rack_min_rtt;
                log.u_bbr.lost = rack->r_ctl.rc_probertt_sndmax_atexit;
                log.u_bbr.pacing_gain = rack_get_output_gain(rack, rsm);
                if (rack->r_ctl.cwnd_to_use < rack->rc_tp->snd_ssthresh) {
                        /* We are in slow start */
                        log.u_bbr.flex7 = 1;
                } else {
                        /* we are on congestion avoidance */
                        log.u_bbr.flex7 = 0;
                }
                log.u_bbr.flex8 = method;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.cwnd_gain = rack->rc_gp_saw_rec;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->rc_gp_saw_ss;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->rc_gp_saw_ca;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->use_fixed_rate;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->rc_always_pace;
                log.u_bbr.cwnd_gain <<= 1;
                log.u_bbr.cwnd_gain |= rack->gp_ready;
                log.u_bbr.bbr_substate = quality;
                log.u_bbr.bbr_state = rack->dgp_on;
                log.u_bbr.bbr_state <<= 1;
                log.u_bbr.bbr_state |= rack->rc_pace_to_cwnd;
                log.u_bbr.bbr_state <<= 2;
                TCP_LOG_EVENTP(rack->rc_tp, NULL,
                    &rack->rc_inp->inp_socket->so_rcv,
                    &rack->rc_inp->inp_socket->so_snd,
                    BBR_LOG_HPTSI_CALC, 0,
                    0, &log, false, &tv);
        }
}

static uint32_t
rack_get_pacing_len(struct tcp_rack *rack, uint64_t bw, uint32_t mss)
{
        uint32_t new_tso, user_max, pace_one;

        user_max = rack->rc_user_set_max_segs * mss;
        if (rack->rc_force_max_seg) {
                return (user_max);
        }
        if (rack->use_fixed_rate &&
            ((rack->r_ctl.crte == NULL) ||
             (bw != rack->r_ctl.crte->rate))) {
                /* Use the user mss since we are not exactly matched */
                return (user_max);
        }
        if (rack_pace_one_seg ||
            (rack->r_ctl.rc_user_set_min_segs == 1))
                pace_one = 1;
        else
                pace_one = 0;

        new_tso = tcp_get_pacing_burst_size_w_divisor(rack->rc_tp, bw, mss,
                     pace_one, rack->r_ctl.crte, NULL, rack->r_ctl.pace_len_divisor);
        if (new_tso > user_max)
                new_tso = user_max;
        if (rack->rc_hybrid_mode && rack->r_ctl.client_suggested_maxseg) {
                if (((uint32_t)rack->r_ctl.client_suggested_maxseg * mss) > new_tso)
                        new_tso = (uint32_t)rack->r_ctl.client_suggested_maxseg * mss;
        }
        if (rack->r_ctl.rc_user_set_min_segs &&
            ((rack->r_ctl.rc_user_set_min_segs * mss) > new_tso))
            new_tso = rack->r_ctl.rc_user_set_min_segs * mss;
        return (new_tso);
}

static uint64_t
rack_arrive_at_discounted_rate(struct tcp_rack *rack, uint64_t window_input, uint32_t *rate_set, uint32_t *gain_b)
{
        uint64_t reduced_win;
        uint32_t gain;

        if (window_input < rc_init_window(rack)) {
                /*
                 * The cwnd is collapsed to
                 * nearly zero, maybe because of a time-out?
                 * Lets drop back to the lt-bw.
                 */
                reduced_win = rack_get_lt_bw(rack);
                /* Set the flag so the caller knows its a rate and not a reduced window */
                *rate_set = 1;
                gain = 100;
        } else if  (IN_RECOVERY(rack->rc_tp->t_flags)) {
                /*
                 * If we are in recover our cwnd needs to be less for
                 * our pacing consideration.
                 */
                if (rack->rack_hibeta == 0) {
                        reduced_win = window_input / 2;
                        gain = 50;
                } else {
                        reduced_win = window_input * rack->r_ctl.saved_hibeta;
                        reduced_win /= 100;
                        gain = rack->r_ctl.saved_hibeta;
                }
        } else {
                /*
                 * Apply Timely factor to increase/decrease the
                 * amount we are pacing at.
                 */
                gain = rack_get_output_gain(rack, NULL);
                if (gain > rack_gain_p5_ub) {
                        gain = rack_gain_p5_ub;
                }
                reduced_win = window_input * gain;
                reduced_win /= 100;
        }
        if (gain_b != NULL)
                *gain_b = gain;
        /*
         * What is being returned here is a trimmed down
         * window values in all cases where rate_set is left
         * at 0. In one case we actually return the rate (lt_bw).
         * the "reduced_win" is returned as a slimmed down cwnd that
         * is then calculated by the caller into a rate when rate_set
         * is 0.
         */
        return (reduced_win);
}

static int32_t
pace_to_fill_cwnd(struct tcp_rack *rack, int32_t pacing_delay, uint32_t len, uint32_t segsiz, int *capped, uint64_t *rate_wanted, uint8_t non_paced)
{
        uint64_t lentim, fill_bw;

        rack->r_via_fill_cw = 0;
        if (ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked) > rack->r_ctl.cwnd_to_use)
                return (pacing_delay);
        if ((ctf_outstanding(rack->rc_tp) + (segsiz-1)) > rack->rc_tp->snd_wnd)
                return (pacing_delay);
        if (rack->r_ctl.rc_last_us_rtt == 0)
                return (pacing_delay);
        if (rack->rc_pace_fill_if_rttin_range &&
            (rack->r_ctl.rc_last_us_rtt >=
             (get_filter_value_small(&rack->r_ctl.rc_gp_min_rtt) * rack->rtt_limit_mul))) {
                /* The rtt is huge, N * smallest, lets not fill */
                return (pacing_delay);
        }
        if (rack->r_ctl.fillcw_cap && *rate_wanted >= rack->r_ctl.fillcw_cap)
                return (pacing_delay);
        /*
         * first lets calculate the b/w based on the last us-rtt
         * and the smallest send window.
         */
        fill_bw = min(rack->rc_tp->snd_cwnd, rack->r_ctl.cwnd_to_use);
        if (rack->rc_fillcw_apply_discount) {
                uint32_t rate_set = 0;

                fill_bw = rack_arrive_at_discounted_rate(rack, fill_bw, &rate_set, NULL);
                if (rate_set) {
                        goto at_lt_bw;
                }
        }
        /* Take the rwnd if its smaller */
        if (fill_bw > rack->rc_tp->snd_wnd)
                fill_bw = rack->rc_tp->snd_wnd;
        /* Now lets make it into a b/w */
        fill_bw *= (uint64_t)HPTS_USEC_IN_SEC;
        fill_bw /= (uint64_t)rack->r_ctl.rc_last_us_rtt;
        /* Adjust to any cap */
        if (rack->r_ctl.fillcw_cap && fill_bw >= rack->r_ctl.fillcw_cap)
                fill_bw = rack->r_ctl.fillcw_cap;

at_lt_bw:
        if (rack_bw_multipler > 0) {
                /*
                 * We want to limit fill-cw to the some multiplier
                 * of the max(lt_bw, gp_est). The normal default
                 * is 0 for off, so a sysctl has enabled it.
                 */
                uint64_t lt_bw, gp, rate;

                gp = rack_get_gp_est(rack);
                lt_bw = rack_get_lt_bw(rack);
                if (lt_bw > gp)
                        rate = lt_bw;
                else
                        rate = gp;
                rate *= rack_bw_multipler;
                rate /= 100;
                if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                        union tcp_log_stackspecific log;
                        struct timeval tv;

                        memset(&log, 0, sizeof(log));
                        log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                        log.u_bbr.flex1 = rack_bw_multipler;
                        log.u_bbr.flex2 = len;
                        log.u_bbr.cur_del_rate = gp;
                        log.u_bbr.delRate = lt_bw;
                        log.u_bbr.bw_inuse = rate;
                        log.u_bbr.rttProp = fill_bw;
                        log.u_bbr.flex8 = 44;
                        tcp_log_event(rack->rc_tp, NULL, NULL, NULL,
                                      BBR_LOG_CWND, 0,
                                      0, &log, false, NULL,
                                      __func__, __LINE__, &tv);
                }
                if (fill_bw > rate)
                        fill_bw = rate;
        }
        /* We are below the min b/w */
        if (non_paced)
                *rate_wanted = fill_bw;
        if ((fill_bw < RACK_MIN_BW) || (fill_bw < *rate_wanted))
                return (pacing_delay);
        rack->r_via_fill_cw = 1;
        if (rack->r_rack_hw_rate_caps &&
            (rack->r_ctl.crte != NULL)) {
                uint64_t high_rate;

                high_rate = tcp_hw_highest_rate(rack->r_ctl.crte);
                if (fill_bw > high_rate) {
                        /* We are capping bw at the highest rate table entry */
                        if (*rate_wanted > high_rate) {
                                /* The original rate was also capped */
                                rack->r_via_fill_cw = 0;
                        }
                        rack_log_hdwr_pacing(rack,
                                             fill_bw, high_rate, __LINE__,
                                             0, 3);
                        fill_bw = high_rate;
                        if (capped)
                                *capped = 1;
                }
        } else if ((rack->r_ctl.crte == NULL) &&
                   (rack->rack_hdrw_pacing == 0) &&
                   (rack->rack_hdw_pace_ena) &&
                   rack->r_rack_hw_rate_caps &&
                   (rack->rack_attempt_hdwr_pace == 0) &&
                   (rack->rc_inp->inp_route.ro_nh != NULL) &&
                   (rack->rc_inp->inp_route.ro_nh->nh_ifp != NULL)) {
                /*
                 * Ok we may have a first attempt that is greater than our top rate
                 * lets check.
                 */
                uint64_t high_rate;

                high_rate = tcp_hw_highest_rate_ifp(rack->rc_inp->inp_route.ro_nh->nh_ifp, rack->rc_inp);
                if (high_rate) {
                        if (fill_bw > high_rate) {
                                fill_bw = high_rate;
                                if (capped)
                                        *capped = 1;
                        }
                }
        }
        if (rack->r_ctl.bw_rate_cap && (fill_bw > rack->r_ctl.bw_rate_cap)) {
                rack_log_hybrid_bw(rack, rack->rc_tp->snd_max,
                                   fill_bw, 0, 0, HYBRID_LOG_RATE_CAP, 2, NULL, __LINE__);
                fill_bw = rack->r_ctl.bw_rate_cap;
        }
        /*
         * Ok fill_bw holds our mythical b/w to fill the cwnd
         * in an rtt (unless it was capped), what does that
         * time wise equate too?
         */
        lentim = (uint64_t)(len) * (uint64_t)HPTS_USEC_IN_SEC;
        lentim /= fill_bw;
        *rate_wanted = fill_bw;
        if (non_paced || (lentim < pacing_delay)) {
                rack_log_pacing_delay_calc(rack, len, pacing_delay, fill_bw,
                                           0, lentim, 12, __LINE__, NULL, 0);
                return ((int32_t)lentim);
        } else
                return (pacing_delay);
}

static int32_t
rack_get_pacing_delay(struct tcp_rack *rack, struct tcpcb *tp, uint32_t len, struct rack_sendmap *rsm, uint32_t segsiz, int line)
{
        uint64_t srtt;
        int32_t pacing_delay = 0;
        int can_start_hw_pacing = 1;
        int err;
        int pace_one;

        if (rack_pace_one_seg ||
            (rack->r_ctl.rc_user_set_min_segs == 1))
                pace_one = 1;
        else
                pace_one = 0;
        if (rack->rc_always_pace == 0) {
                /*
                 * We use the most optimistic possible cwnd/srtt for
                 * sending calculations. This will make our
                 * calculation anticipate getting more through
                 * quicker then possible. But thats ok we don't want
                 * the peer to have a gap in data sending.
                 */
                uint64_t cwnd, tr_perms = 0;
                int32_t reduce;

        old_method:
                /*
                 * We keep no precise pacing with the old method
                 * instead we use the pacer to mitigate bursts.
                 */
                if (rack->r_ctl.rc_rack_min_rtt)
                        srtt = rack->r_ctl.rc_rack_min_rtt;
                else
                        srtt = max(tp->t_srtt, 1);
                if (rack->r_ctl.rc_rack_largest_cwnd)
                        cwnd = rack->r_ctl.rc_rack_largest_cwnd;
                else
                        cwnd = rack->r_ctl.cwnd_to_use;
                /* Inflate cwnd by 1000 so srtt of usecs is in ms */
                tr_perms = (cwnd * 1000) / srtt;
                if (tr_perms == 0) {
                        tr_perms = ctf_fixed_maxseg(tp);
                }
                /*
                 * Calculate how long this will take to drain, if
                 * the calculation comes out to zero, thats ok we
                 * will use send_a_lot to possibly spin around for
                 * more increasing tot_len_this_send to the point
                 * that its going to require a pace, or we hit the
                 * cwnd. Which in that case we are just waiting for
                 * a ACK.
                 */
                pacing_delay = len / tr_perms;
                /* Now do we reduce the time so we don't run dry? */
                if (pacing_delay && rack_pacing_delay_reduction) {
                        reduce = (pacing_delay / rack_pacing_delay_reduction);
                        if (reduce < pacing_delay) {
                                pacing_delay -= reduce;
                        } else
                                pacing_delay = 0;
                } else
                        reduce = 0;
                pacing_delay *= HPTS_USEC_IN_MSEC;
                if (rack->rc_pace_to_cwnd) {
                        uint64_t rate_wanted = 0;

                        pacing_delay = pace_to_fill_cwnd(rack, pacing_delay, len, segsiz, NULL, &rate_wanted, 1);
                        rack->rc_ack_can_sendout_data = 1;
                        rack_log_pacing_delay_calc(rack, len, pacing_delay, rate_wanted, 0, 0, 14, __LINE__, NULL, 0);
                } else
                        rack_log_pacing_delay_calc(rack, len, pacing_delay, tr_perms, reduce, 0, 7, __LINE__, NULL, 0);
                /*******************************************************/
                /* RRS: We insert non-paced call to stats here for len */
                /*******************************************************/
        } else {
                uint64_t bw_est, res, lentim, rate_wanted;
                uint32_t segs, oh;
                int capped = 0;
                int prev_fill;

                if ((rack->r_rr_config == 1) && rsm) {
                        return (rack->r_ctl.rc_min_to);
                }
                if (rack->use_fixed_rate) {
                        rate_wanted = bw_est = rack_get_fixed_pacing_bw(rack);
                } else if ((rack->r_ctl.init_rate == 0) &&
                           (rack->r_ctl.gp_bw == 0)) {
                        /* no way to yet do an estimate */
                        bw_est = rate_wanted = 0;
                } else if (rack->dgp_on) {
                        bw_est = rack_get_bw(rack);
                        rate_wanted = rack_get_output_bw(rack, bw_est, rsm, &capped);
                } else {
                        uint32_t gain, rate_set = 0;

                        rate_wanted = min(rack->rc_tp->snd_cwnd, rack->r_ctl.cwnd_to_use);
                        rate_wanted = rack_arrive_at_discounted_rate(rack, rate_wanted, &rate_set, &gain);
                        if (rate_set == 0) {
                                if (rate_wanted > rack->rc_tp->snd_wnd)
                                        rate_wanted = rack->rc_tp->snd_wnd;
                                /* Now lets make it into a b/w */
                                rate_wanted *= (uint64_t)HPTS_USEC_IN_SEC;
                                rate_wanted /= (uint64_t)rack->r_ctl.rc_last_us_rtt;
                        }
                        bw_est = rate_wanted;
                        rack_log_pacing_delay_calc(rack, rack->rc_tp->snd_cwnd,
                                                   rack->r_ctl.cwnd_to_use,
                                                   rate_wanted, bw_est,
                                                   rack->r_ctl.rc_last_us_rtt,
                                                   88, __LINE__, NULL, gain);
                }
                if (((bw_est == 0) || (rate_wanted == 0) || (rack->gp_ready == 0)) &&
                    (rack->use_fixed_rate == 0)) {
                        /*
                         * No way yet to make a b/w estimate or
                         * our raise is set incorrectly.
                         */
                        goto old_method;
                }
                rack_rate_cap_bw(rack, &rate_wanted, &capped);
                /* We need to account for all the overheads */
                segs = (len + segsiz - 1) / segsiz;
                /*
                 * We need the diff between 1514 bytes (e-mtu with e-hdr)
                 * and how much data we put in each packet. Yes this
                 * means we may be off if we are larger than 1500 bytes
                 * or smaller. But this just makes us more conservative.
                 */

                oh =  (tp->t_maxseg - segsiz) + sizeof(struct tcphdr);
                if (rack->r_is_v6) {
#ifdef INET6
                        oh += sizeof(struct ip6_hdr);
#endif
                } else {
#ifdef INET
                        oh += sizeof(struct ip);
#endif
                }
                /* We add a fixed 14 for the ethernet header */
                oh += 14;
                segs *= oh;
                lentim = (uint64_t)(len + segs) * (uint64_t)HPTS_USEC_IN_SEC;
                res = lentim / rate_wanted;
                pacing_delay = (uint32_t)res;
                if (rack_hw_rate_min &&
                    (rate_wanted < rack_hw_rate_min)) {
                        can_start_hw_pacing = 0;
                        if (rack->r_ctl.crte) {
                                /*
                                 * Ok we need to release it, we
                                 * have fallen too low.
                                 */
                                tcp_rel_pacing_rate(rack->r_ctl.crte, rack->rc_tp);
                                rack->r_ctl.crte = NULL;
                                rack->rack_attempt_hdwr_pace = 0;
                                rack->rack_hdrw_pacing = 0;
                        }
                }
                if (rack->r_ctl.crte &&
                    (tcp_hw_highest_rate(rack->r_ctl.crte) < rate_wanted)) {
                        /*
                         * We want more than the hardware can give us,
                         * don't start any hw pacing.
                         */
                        can_start_hw_pacing = 0;
                        if (rack->r_rack_hw_rate_caps == 0) {
                                /*
                                 * Ok we need to release it, we
                                 * want more than the card can give us and
                                 * no rate cap is in place. Set it up so
                                 * when we want less we can retry.
                                 */
                                tcp_rel_pacing_rate(rack->r_ctl.crte, rack->rc_tp);
                                rack->r_ctl.crte = NULL;
                                rack->rack_attempt_hdwr_pace = 0;
                                rack->rack_hdrw_pacing = 0;
                        }
                }
                if ((rack->r_ctl.crte != NULL) && (rack->rc_inp->inp_snd_tag == NULL)) {
                        /*
                         * We lost our rate somehow, this can happen
                         * if the interface changed underneath us.
                         */
                        tcp_rel_pacing_rate(rack->r_ctl.crte, rack->rc_tp);
                        rack->r_ctl.crte = NULL;
                        /* Lets re-allow attempting to setup pacing */
                        rack->rack_hdrw_pacing = 0;
                        rack->rack_attempt_hdwr_pace = 0;
                        rack_log_hdwr_pacing(rack,
                                             rate_wanted, bw_est, __LINE__,
                                             0, 6);
                }
                prev_fill = rack->r_via_fill_cw;
                if ((rack->rc_pace_to_cwnd) &&
                    (capped == 0) &&
                    (rack->dgp_on == 1) &&
                    (rack->use_fixed_rate == 0) &&
                    (rack->in_probe_rtt == 0) &&
                    (IN_FASTRECOVERY(rack->rc_tp->t_flags) == 0)) {
                        /*
                         * We want to pace at our rate *or* faster to
                         * fill the cwnd to the max if its not full.
                         */
                        pacing_delay = pace_to_fill_cwnd(rack, pacing_delay, (len+segs), segsiz, &capped, &rate_wanted, 0);
                        /* Re-check to make sure we are not exceeding our max b/w */
                        if ((rack->r_ctl.crte != NULL) &&
                            (tcp_hw_highest_rate(rack->r_ctl.crte) < rate_wanted)) {
                                /*
                                 * We want more than the hardware can give us,
                                 * don't start any hw pacing.
                                 */
                                can_start_hw_pacing = 0;
                                if (rack->r_rack_hw_rate_caps == 0) {
                                        /*
                                         * Ok we need to release it, we
                                         * want more than the card can give us and
                                         * no rate cap is in place. Set it up so
                                         * when we want less we can retry.
                                         */
                                        tcp_rel_pacing_rate(rack->r_ctl.crte, rack->rc_tp);
                                        rack->r_ctl.crte = NULL;
                                        rack->rack_attempt_hdwr_pace = 0;
                                        rack->rack_hdrw_pacing = 0;
                                        rack_set_pace_segments(rack->rc_tp, rack, __LINE__, NULL);
                                }
                        }
                }
                if ((rack->rc_inp->inp_route.ro_nh != NULL) &&
                    (rack->rc_inp->inp_route.ro_nh->nh_ifp != NULL)) {
                        if ((rack->rack_hdw_pace_ena) &&
                            (can_start_hw_pacing > 0) &&
                            (rack->rack_hdrw_pacing == 0) &&
                            (rack->rack_attempt_hdwr_pace == 0)) {
                                /*
                                 * Lets attempt to turn on hardware pacing
                                 * if we can.
                                 */
                                rack->rack_attempt_hdwr_pace = 1;
                                rack->r_ctl.crte = tcp_set_pacing_rate(rack->rc_tp,
                                                                       rack->rc_inp->inp_route.ro_nh->nh_ifp,
                                                                       rate_wanted,
                                                                       RS_PACING_GEQ,
                                                                       &err, &rack->r_ctl.crte_prev_rate);
                                if (rack->r_ctl.crte) {
                                        rack->rack_hdrw_pacing = 1;
                                        rack->r_ctl.rc_pace_max_segs = tcp_get_pacing_burst_size_w_divisor(tp, rate_wanted, segsiz,
                                                                                                           pace_one, rack->r_ctl.crte,
                                                                                                           NULL, rack->r_ctl.pace_len_divisor);
                                        rack_log_hdwr_pacing(rack,
                                                             rate_wanted, rack->r_ctl.crte->rate, __LINE__,
                                                             err, 0);
                                        rack->r_ctl.last_hw_bw_req = rate_wanted;
                                } else {
                                        counter_u64_add(rack_hw_pace_init_fail, 1);
                                }
                        } else if (rack->rack_hdrw_pacing &&
                                   (rack->r_ctl.last_hw_bw_req != rate_wanted)) {
                                /* Do we need to adjust our rate? */
                                const struct tcp_hwrate_limit_table *nrte;

                                if (rack->r_up_only &&
                                    (rate_wanted < rack->r_ctl.crte->rate)) {
                                        /**
                                         * We have four possible states here
                                         * having to do with the previous time
                                         * and this time.
                                         *   previous  |  this-time
                                         * A)     0      |     0   -- fill_cw not in the picture
                                         * B)     1      |     0   -- we were doing a fill-cw but now are not
                                         * C)     1      |     1   -- all rates from fill_cw
                                         * D)     0      |     1   -- we were doing non-fill and now we are filling
                                         *
                                         * For case A, C and D we don't allow a drop. But for
                                         * case B where we now our on our steady rate we do
                                         * allow a drop.
                                         *
                                         */
                                        if (!((prev_fill == 1) && (rack->r_via_fill_cw == 0)))
                                                goto done_w_hdwr;
                                }
                                if ((rate_wanted > rack->r_ctl.crte->rate) ||
                                    (rate_wanted <= rack->r_ctl.crte_prev_rate)) {
                                        if (rack_hw_rate_to_low &&
                                            (bw_est < rack_hw_rate_to_low)) {
                                                /*
                                                 * The pacing rate is too low for hardware, but
                                                 * do allow hardware pacing to be restarted.
                                                 */
                                                rack_log_hdwr_pacing(rack,
                                                                     bw_est, rack->r_ctl.crte->rate, __LINE__,
                                                                     0, 5);
                                                tcp_rel_pacing_rate(rack->r_ctl.crte, rack->rc_tp);
                                                rack->r_ctl.crte = NULL;
                                                rack->rack_attempt_hdwr_pace = 0;
                                                rack->rack_hdrw_pacing = 0;
                                                rack_set_pace_segments(rack->rc_tp, rack, __LINE__, &rate_wanted);
                                                goto done_w_hdwr;
                                        }
                                        nrte = tcp_chg_pacing_rate(rack->r_ctl.crte,
                                                                   rack->rc_tp,
                                                                   rack->rc_inp->inp_route.ro_nh->nh_ifp,
                                                                   rate_wanted,
                                                                   RS_PACING_GEQ,
                                                                   &err, &rack->r_ctl.crte_prev_rate);
                                        if (nrte == NULL) {
                                                /*
                                                 * Lost the rate, lets drop hardware pacing
                                                 * period.
                                                 */
                                                rack->rack_hdrw_pacing = 0;
                                                rack->r_ctl.crte = NULL;
                                                rack_log_hdwr_pacing(rack,
                                                                     rate_wanted, 0, __LINE__,
                                                                     err, 1);
                                                rack_set_pace_segments(rack->rc_tp, rack, __LINE__, &rate_wanted);
                                                counter_u64_add(rack_hw_pace_lost, 1);
                                        } else if (nrte != rack->r_ctl.crte) {
                                                rack->r_ctl.crte = nrte;
                                                rack->r_ctl.rc_pace_max_segs = tcp_get_pacing_burst_size_w_divisor(tp, rate_wanted,
                                                                                                                   segsiz, pace_one, rack->r_ctl.crte,
                                                                                                                   NULL, rack->r_ctl.pace_len_divisor);
                                                rack_log_hdwr_pacing(rack,
                                                                     rate_wanted, rack->r_ctl.crte->rate, __LINE__,
                                                                     err, 2);
                                                rack->r_ctl.last_hw_bw_req = rate_wanted;
                                        }
                                } else {
                                        /* We just need to adjust the segment size */
                                        rack_set_pace_segments(rack->rc_tp, rack, __LINE__, &rate_wanted);
                                        rack_log_hdwr_pacing(rack,
                                                             rate_wanted, rack->r_ctl.crte->rate, __LINE__,
                                                             0, 4);
                                        rack->r_ctl.last_hw_bw_req = rate_wanted;
                                }
                        }
                }
        done_w_hdwr:
                if (rack_limit_time_with_srtt &&
                    (rack->use_fixed_rate == 0) &&
                    (rack->rack_hdrw_pacing == 0)) {
                        /*
                         * Sanity check, we do not allow the pacing delay
                         * to be longer than the SRTT of the path. If it is
                         * a slow path, then adding a packet should increase
                         * the RTT and compensate for this i.e. the srtt will
                         * be greater so the allowed pacing time will be greater.
                         *
                         * Note this restriction is not for where a peak rate
                         * is set, we are doing fixed pacing or hardware pacing.
                         */
                        if (rack->rc_tp->t_srtt)
                                srtt = rack->rc_tp->t_srtt;
                        else
                                srtt = RACK_INITIAL_RTO * HPTS_USEC_IN_MSEC;    /* its in ms convert */
                        if (srtt < (uint64_t)pacing_delay) {
                                rack_log_pacing_delay_calc(rack, srtt, pacing_delay, rate_wanted, bw_est, lentim, 99, __LINE__, NULL, 0);
                                pacing_delay = srtt;
                        }
                }
                /*******************************************************************/
                /* RRS: We insert paced call to stats here for len and rate_wanted */
                /*******************************************************************/
                rack_log_pacing_delay_calc(rack, len, pacing_delay, rate_wanted, bw_est, lentim, 2, __LINE__, rsm, 0);
        }
        if (rack->r_ctl.crte && (rack->r_ctl.crte->rs_num_enobufs > 0)) {
                /*
                 * If this rate is seeing enobufs when it
                 * goes to send then either the nic is out
                 * of gas or we are mis-estimating the time
                 * somehow and not letting the queue empty
                 * completely. Lets add to the pacing time.
                 */
                int hw_boost_delay;

                hw_boost_delay = rack->r_ctl.crte->time_between * rack_enobuf_hw_boost_mult;
                if (hw_boost_delay > rack_enobuf_hw_max)
                        hw_boost_delay = rack_enobuf_hw_max;
                else if (hw_boost_delay < rack_enobuf_hw_min)
                        hw_boost_delay = rack_enobuf_hw_min;
                pacing_delay += hw_boost_delay;
        }
        return (pacing_delay);
}

static void
rack_start_gp_measurement(struct tcpcb *tp, struct tcp_rack *rack,
    tcp_seq startseq, uint32_t sb_offset)
{
        struct rack_sendmap *my_rsm = NULL;

        if (tp->t_state < TCPS_ESTABLISHED) {
                /*
                 * We don't start any measurements if we are
                 * not at least established.
                 */
                return;
        }
        if (tp->t_state >= TCPS_FIN_WAIT_1) {
                /*
                 * We will get no more data into the SB
                 * this means we need to have the data available
                 * before we start a measurement.
                 */

                if (sbavail(&tptosocket(tp)->so_snd) <
                    max(rc_init_window(rack),
                        (MIN_GP_WIN * ctf_fixed_maxseg(tp)))) {
                        /* Nope not enough data */
                        return;
                }
        }
        tp->t_flags |= TF_GPUTINPROG;
        rack->r_ctl.rc_gp_cumack_ts = 0;
        rack->r_ctl.rc_gp_lowrtt = 0xffffffff;
        rack->r_ctl.rc_gp_high_rwnd = rack->rc_tp->snd_wnd;
        tp->gput_seq = startseq;
        rack->app_limited_needs_set = 0;
        if (rack->in_probe_rtt)
                rack->measure_saw_probe_rtt = 1;
        else if ((rack->measure_saw_probe_rtt) &&
                 (SEQ_GEQ(tp->gput_seq, rack->r_ctl.rc_probertt_sndmax_atexit)))
                rack->measure_saw_probe_rtt = 0;
        if (rack->rc_gp_filled)
                tp->gput_ts = rack->r_ctl.last_cumack_advance;
        else {
                /* Special case initial measurement */
                struct timeval tv;

                tp->gput_ts = tcp_get_usecs(&tv);
                rack->r_ctl.rc_gp_output_ts = rack_to_usec_ts(&tv);
        }
        /*
         * We take a guess out into the future,
         * if we have no measurement and no
         * initial rate, we measure the first
         * initial-windows worth of data to
         * speed up getting some GP measurement and
         * thus start pacing.
         */
        if ((rack->rc_gp_filled == 0) && (rack->r_ctl.init_rate == 0)) {
                rack->app_limited_needs_set = 1;
                tp->gput_ack = startseq + max(rc_init_window(rack),
                                              (MIN_GP_WIN * ctf_fixed_maxseg(tp)));
                rack_log_pacing_delay_calc(rack,
                                           tp->gput_seq,
                                           tp->gput_ack,
                                           0,
                                           tp->gput_ts,
                                           (((uint64_t)rack->r_ctl.rc_app_limited_cnt << 32) | (uint64_t)rack->r_ctl.rc_gp_output_ts),
                                           9,
                                           __LINE__, NULL, 0);
                rack_tend_gp_marks(tp, rack);
                rack_log_gpset(rack, tp->gput_ack, 0, 0, __LINE__, 1, NULL);
                return;
        }
        if (sb_offset) {
                /*
                 * We are out somewhere in the sb
                 * can we use the already outstanding data?
                 */

                if (rack->r_ctl.rc_app_limited_cnt == 0) {
                        /*
                         * Yes first one is good and in this case
                         * the tp->gput_ts is correctly set based on
                         * the last ack that arrived (no need to
                         * set things up when an ack comes in).
                         */
                        my_rsm = tqhash_min(rack->r_ctl.tqh);
                        if ((my_rsm == NULL) ||
                            (my_rsm->r_rtr_cnt != 1)) {
                                /* retransmission? */
                                goto use_latest;
                        }
                } else {
                        if (rack->r_ctl.rc_first_appl == NULL) {
                                /*
                                 * If rc_first_appl is NULL
                                 * then the cnt should be 0.
                                 * This is probably an error, maybe
                                 * a KASSERT would be approprate.
                                 */
                                goto use_latest;
                        }
                        /*
                         * If we have a marker pointer to the last one that is
                         * app limited we can use that, but we need to set
                         * things up so that when it gets ack'ed we record
                         * the ack time (if its not already acked).
                         */
                        rack->app_limited_needs_set = 1;
                        /*
                         * We want to get to the rsm that is either
                         * next with space i.e. over 1 MSS or the one
                         * after that (after the app-limited).
                         */
                        my_rsm = tqhash_next(rack->r_ctl.tqh, rack->r_ctl.rc_first_appl);
                        if (my_rsm) {
                                if ((my_rsm->r_end - my_rsm->r_start) <= ctf_fixed_maxseg(tp))
                                        /* Have to use the next one */
                                        my_rsm = tqhash_next(rack->r_ctl.tqh, my_rsm);
                                else {
                                        /* Use after the first MSS of it is acked */
                                        tp->gput_seq = my_rsm->r_start + ctf_fixed_maxseg(tp);
                                        goto start_set;
                                }
                        }
                        if ((my_rsm == NULL) ||
                            (my_rsm->r_rtr_cnt != 1)) {
                                /*
                                 * Either its a retransmit or
                                 * the last is the app-limited one.
                                 */
                                goto use_latest;
                        }
                }
                tp->gput_seq = my_rsm->r_start;
start_set:
                if (my_rsm->r_flags & RACK_ACKED) {
                        /*
                         * This one has been acked use the arrival ack time
                         */
                        struct rack_sendmap *nrsm;

                        tp->gput_ts = (uint32_t)my_rsm->r_ack_arrival;
                        rack->app_limited_needs_set = 0;
                        /*
                         * Ok in this path we need to use the r_end now
                         * since this guy is the starting ack.
                         */
                        tp->gput_seq = my_rsm->r_end;
                        /*
                         * We also need to adjust up the sendtime
                         * to the send of the next data after my_rsm.
                         */
                        nrsm = tqhash_next(rack->r_ctl.tqh, my_rsm);
                        if (nrsm != NULL)
                                my_rsm = nrsm;
                        else {
                                /*
                                 * The next as not been sent, thats the
                                 * case for using the latest.
                                 */
                                goto use_latest;
                        }
                }
                rack->r_ctl.rc_gp_output_ts = my_rsm->r_tim_lastsent[0];
                tp->gput_ack = tp->gput_seq + rack_get_measure_window(tp, rack);
                rack->r_ctl.rc_gp_cumack_ts = 0;
                if ((rack->r_ctl.cleared_app_ack == 1) &&
                    (SEQ_GEQ(tp->gput_seq, rack->r_ctl.cleared_app_ack_seq))) {
                        /*
                         * We just cleared an application limited period
                         * so the next seq out needs to skip the first
                         * ack.
                         */
                        rack->app_limited_needs_set = 1;
                        rack->r_ctl.cleared_app_ack = 0;
                }
                rack_log_pacing_delay_calc(rack,
                                           tp->gput_seq,
                                           tp->gput_ack,
                                           (uintptr_t)my_rsm,
                                           tp->gput_ts,
                                           (((uint64_t)rack->r_ctl.rc_app_limited_cnt << 32) | (uint64_t)rack->r_ctl.rc_gp_output_ts),
                                           9,
                                           __LINE__, my_rsm, 0);
                /* Now lets make sure all are marked as they should be */
                rack_tend_gp_marks(tp, rack);
                rack_log_gpset(rack, tp->gput_ack, 0, 0, __LINE__, 1, NULL);
                return;
        }

use_latest:
        /*
         * We don't know how long we may have been
         * idle or if this is the first-send. Lets
         * setup the flag so we will trim off
         * the first ack'd data so we get a true
         * measurement.
         */
        rack->app_limited_needs_set = 1;
        tp->gput_ack = startseq + rack_get_measure_window(tp, rack);
        rack->r_ctl.rc_gp_cumack_ts = 0;
        /* Find this guy so we can pull the send time */
        my_rsm = tqhash_find(rack->r_ctl.tqh, startseq);
        if (my_rsm) {
                rack->r_ctl.rc_gp_output_ts = my_rsm->r_tim_lastsent[0];
                if (my_rsm->r_flags & RACK_ACKED) {
                        /*
                         * Unlikely since its probably what was
                         * just transmitted (but I am paranoid).
                         */
                        tp->gput_ts = (uint32_t)my_rsm->r_ack_arrival;
                        rack->app_limited_needs_set = 0;
                }
                if (SEQ_LT(my_rsm->r_start, tp->gput_seq)) {
                        /* This also is unlikely */
                        tp->gput_seq = my_rsm->r_start;
                }
        } else {
                /*
                 * TSNH unless we have some send-map limit,
                 * and even at that it should not be hitting
                 * that limit (we should have stopped sending).
                 */
                struct timeval tv;

                microuptime(&tv);
                rack->r_ctl.rc_gp_output_ts = rack_to_usec_ts(&tv);
        }
        rack_tend_gp_marks(tp, rack);
        rack_log_pacing_delay_calc(rack,
                                   tp->gput_seq,
                                   tp->gput_ack,
                                   (uintptr_t)my_rsm,
                                   tp->gput_ts,
                                   (((uint64_t)rack->r_ctl.rc_app_limited_cnt << 32) | (uint64_t)rack->r_ctl.rc_gp_output_ts),
                                   9, __LINE__, NULL, 0);
        rack_log_gpset(rack, tp->gput_ack, 0, 0, __LINE__, 1, NULL);
}

static inline uint32_t
rack_what_can_we_send(struct tcpcb *tp, struct tcp_rack *rack,  uint32_t cwnd_to_use,
    uint32_t avail, int32_t sb_offset)
{
        uint32_t len;
        uint32_t sendwin;

        if (tp->snd_wnd > cwnd_to_use)
                sendwin = cwnd_to_use;
        else
                sendwin = tp->snd_wnd;
        if (ctf_outstanding(tp) >= tp->snd_wnd) {
                /* We never want to go over our peers rcv-window */
                len = 0;
        } else {
                uint32_t flight;

                flight = ctf_flight_size(tp, rack->r_ctl.rc_sacked);
                if (flight >= sendwin) {
                        /*
                         * We have in flight what we are allowed by cwnd (if
                         * it was rwnd blocking it would have hit above out
                         * >= tp->snd_wnd).
                         */
                        return (0);
                }
                len = sendwin - flight;
                if ((len + ctf_outstanding(tp)) > tp->snd_wnd) {
                        /* We would send too much (beyond the rwnd) */
                        len = tp->snd_wnd - ctf_outstanding(tp);
                }
                if ((len + sb_offset) > avail) {
                        /*
                         * We don't have that much in the SB, how much is
                         * there?
                         */
                        len = avail - sb_offset;
                }
        }
        return (len);
}

static void
rack_log_fsb(struct tcp_rack *rack, struct tcpcb *tp, struct socket *so, uint32_t flags,
             unsigned ipoptlen, int32_t orig_len, int32_t len, int error,
             int rsm_is_null, int optlen, int line, uint16_t mode)
{
        if (rack_verbose_logging && tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;
                struct timeval tv;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = error;
                log.u_bbr.flex2 = flags;
                log.u_bbr.flex3 = rsm_is_null;
                log.u_bbr.flex4 = ipoptlen;
                log.u_bbr.flex5 = tp->rcv_numsacks;
                log.u_bbr.flex6 = rack->r_ctl.rc_agg_early;
                log.u_bbr.flex7 = optlen;
                log.u_bbr.flex8 = rack->r_fsb_inited;
                log.u_bbr.applimited = rack->r_fast_output;
                log.u_bbr.bw_inuse = rack_get_bw(rack);
                log.u_bbr.pacing_gain = rack_get_output_gain(rack, NULL);
                log.u_bbr.cwnd_gain = mode;
                log.u_bbr.pkts_out = orig_len;
                log.u_bbr.lt_epoch = len;
                log.u_bbr.delivered = line;
                log.u_bbr.timeStamp = tcp_get_usecs(&tv);
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                tcp_log_event(tp, NULL, &so->so_rcv, &so->so_snd, TCP_LOG_FSB, 0,
                               len, &log, false, NULL, __func__, __LINE__, &tv);
        }
}


static struct mbuf *
rack_fo_base_copym(struct mbuf *the_m, uint32_t the_off, int32_t *plen,
                   struct rack_fast_send_blk *fsb,
                   int32_t seglimit, int32_t segsize, int hw_tls)
{
#ifdef KERN_TLS
        struct ktls_session *tls, *ntls;
#ifdef INVARIANTS
        struct mbuf *start;
#endif
#endif
        struct mbuf *m, *n, **np, *smb;
        struct mbuf *top;
        int32_t off, soff;
        int32_t len = *plen;
        int32_t fragsize;
        int32_t len_cp = 0;
        uint32_t mlen, frags;

        soff = off = the_off;
        smb = m = the_m;
        np = &top;
        top = NULL;
#ifdef KERN_TLS
        if (hw_tls && (m->m_flags & M_EXTPG))
                tls = m->m_epg_tls;
        else
                tls = NULL;
#ifdef INVARIANTS
        start = m;
#endif
#endif
        while (len > 0) {
                if (m == NULL) {
                        *plen = len_cp;
                        break;
                }
#ifdef KERN_TLS
                if (hw_tls) {
                        if (m->m_flags & M_EXTPG)
                                ntls = m->m_epg_tls;
                        else
                                ntls = NULL;

                        /*
                         * Avoid mixing TLS records with handshake
                         * data or TLS records from different
                         * sessions.
                         */
                        if (tls != ntls) {
                                MPASS(m != start);
                                *plen = len_cp;
                                break;
                        }
                }
#endif
                mlen = min(len, m->m_len - off);
                if (seglimit) {
                        /*
                         * For M_EXTPG mbufs, add 3 segments
                         * + 1 in case we are crossing page boundaries
                         * + 2 in case the TLS hdr/trailer are used
                         * It is cheaper to just add the segments
                         * than it is to take the cache miss to look
                         * at the mbuf ext_pgs state in detail.
                         */
                        if (m->m_flags & M_EXTPG) {
                                fragsize = min(segsize, PAGE_SIZE);
                                frags = 3;
                        } else {
                                fragsize = segsize;
                                frags = 0;
                        }

                        /* Break if we really can't fit anymore. */
                        if ((frags + 1) >= seglimit) {
                                *plen = len_cp;
                                break;
                        }

                        /*
                         * Reduce size if you can't copy the whole
                         * mbuf. If we can't copy the whole mbuf, also
                         * adjust len so the loop will end after this
                         * mbuf.
                         */
                        if ((frags + howmany(mlen, fragsize)) >= seglimit) {
                                mlen = (seglimit - frags - 1) * fragsize;
                                len = mlen;
                                *plen = len_cp + len;
                        }
                        frags += howmany(mlen, fragsize);
                        if (frags == 0)
                                frags++;
                        seglimit -= frags;
                        KASSERT(seglimit > 0,
                            ("%s: seglimit went too low", __func__));
                }
                n = m_get(M_NOWAIT, m->m_type);
                *np = n;
                if (n == NULL)
                        goto nospace;
                n->m_len = mlen;
                soff += mlen;
                len_cp += n->m_len;
                if (m->m_flags & (M_EXT | M_EXTPG)) {
                        n->m_data = m->m_data + off;
                        mb_dupcl(n, m);
                } else {
                        bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
                            (u_int)n->m_len);
                }
                len -= n->m_len;
                off = 0;
                m = m->m_next;
                np = &n->m_next;
                if (len || (soff == smb->m_len)) {
                        /*
                         * We have more so we move forward  or
                         * we have consumed the entire mbuf and
                         * len has fell to 0.
                         */
                        soff = 0;
                        smb = m;
                }

        }
        if (fsb != NULL) {
                fsb->m = smb;
                fsb->off = soff;
                if (smb) {
                        /*
                         * Save off the size of the mbuf. We do
                         * this so that we can recognize when it
                         * has been trimmed by sbcut() as acks
                         * come in.
                         */
                        fsb->o_m_len = smb->m_len;
                        fsb->o_t_len = M_TRAILINGROOM(smb);
                } else {
                        /*
                         * This is the case where the next mbuf went to NULL. This
                         * means with this copy we have sent everything in the sb.
                         * In theory we could clear the fast_output flag, but lets
                         * not since its possible that we could get more added
                         * and acks that call the extend function which would let
                         * us send more.
                         */
                        fsb->o_m_len = 0;
                        fsb->o_t_len = 0;
                }
        }
        return (top);
nospace:
        if (top)
                m_freem(top);
        return (NULL);

}

/*
 * This is a copy of m_copym(), taking the TSO segment size/limit
 * constraints into account, and advancing the sndptr as it goes.
 */
static struct mbuf *
rack_fo_m_copym(struct tcp_rack *rack, int32_t *plen,
                int32_t seglimit, int32_t segsize, struct mbuf **s_mb, int *s_soff)
{
        struct mbuf *m, *n;
        int32_t soff;

        m = rack->r_ctl.fsb.m;
        if (M_TRAILINGROOM(m) != rack->r_ctl.fsb.o_t_len) {
                /*
                 * The trailing space changed, mbufs can grow
                 * at the tail but they can't shrink from
                 * it, KASSERT that. Adjust the orig_m_len to
                 * compensate for this change.
                 */
                KASSERT((rack->r_ctl.fsb.o_t_len > M_TRAILINGROOM(m)),
                        ("mbuf:%p rack:%p trailing_space:%jd ots:%u oml:%u mlen:%u\n",
                         m,
                         rack,
                         (intmax_t)M_TRAILINGROOM(m),
                         rack->r_ctl.fsb.o_t_len,
                         rack->r_ctl.fsb.o_m_len,
                         m->m_len));
                rack->r_ctl.fsb.o_m_len += (rack->r_ctl.fsb.o_t_len - M_TRAILINGROOM(m));
                rack->r_ctl.fsb.o_t_len = M_TRAILINGROOM(m);
        }
        if (m->m_len < rack->r_ctl.fsb.o_m_len) {
                /*
                 * Mbuf shrank, trimmed off the top by an ack, our
                 * offset changes.
                 */
                KASSERT((rack->r_ctl.fsb.off >= (rack->r_ctl.fsb.o_m_len - m->m_len)),
                        ("mbuf:%p len:%u rack:%p oml:%u soff:%u\n",
                         m, m->m_len,
                         rack, rack->r_ctl.fsb.o_m_len,
                         rack->r_ctl.fsb.off));

                if (rack->r_ctl.fsb.off >= (rack->r_ctl.fsb.o_m_len- m->m_len))
                        rack->r_ctl.fsb.off -= (rack->r_ctl.fsb.o_m_len - m->m_len);
                else
                        rack->r_ctl.fsb.off = 0;
                rack->r_ctl.fsb.o_m_len = m->m_len;
#ifdef INVARIANTS
        } else if (m->m_len > rack->r_ctl.fsb.o_m_len) {
                panic("rack:%p m:%p m_len grew outside of t_space compensation",
                      rack, m);
#endif
        }
        soff = rack->r_ctl.fsb.off;
        KASSERT(soff >= 0, ("%s, negative off %d", __FUNCTION__, soff));
        KASSERT(*plen >= 0, ("%s, negative len %d", __FUNCTION__, *plen));
        KASSERT(soff < m->m_len, ("%s rack:%p len:%u m:%p m->m_len:%u < off?",
                                 __FUNCTION__,
                                 rack, *plen, m, m->m_len));
        /* Save off the right location before we copy and advance */
        *s_soff = soff;
        *s_mb = rack->r_ctl.fsb.m;
        n = rack_fo_base_copym(m, soff, plen,
                               &rack->r_ctl.fsb,
                               seglimit, segsize, rack->r_ctl.fsb.hw_tls);
        return (n);
}

/* Log the buffer level */
static void
rack_log_queue_level(struct tcpcb *tp, struct tcp_rack *rack,
                     int len, struct timeval *tv,
                     uint32_t cts)
{
        uint32_t p_rate = 0, p_queue = 0, err = 0;
        union tcp_log_stackspecific log;

#ifdef RATELIMIT
        err = in_pcbquery_txrlevel(rack->rc_inp, &p_queue);
        err = in_pcbquery_txrtlmt(rack->rc_inp, &p_rate);
#endif
        memset(&log, 0, sizeof(log));
        log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
        log.u_bbr.flex1 = p_rate;
        log.u_bbr.flex2 = p_queue;
        log.u_bbr.flex4 = (uint32_t)rack->r_ctl.crte->using;
        log.u_bbr.flex5 = (uint32_t)rack->r_ctl.crte->rs_num_enobufs;
        log.u_bbr.flex6 = rack->r_ctl.crte->time_between;
        log.u_bbr.flex7 = 99;
        log.u_bbr.flex8 = 0;
        log.u_bbr.pkts_out = err;
        log.u_bbr.delRate = rack->r_ctl.crte->rate;
        log.u_bbr.timeStamp = cts;
        log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
        tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_HDWR_PACE, 0,
                       len, &log, false, NULL, __func__, __LINE__, tv);

}

static uint32_t
rack_check_queue_level(struct tcp_rack *rack, struct tcpcb *tp,
                       struct timeval *tv, uint32_t cts, int len, uint32_t segsiz)
{
        uint64_t lentime = 0;
#ifdef RATELIMIT
        uint32_t p_rate = 0, p_queue = 0, err;
        union tcp_log_stackspecific log;
        uint64_t bw;

        err = in_pcbquery_txrlevel(rack->rc_inp, &p_queue);
        /* Failed or queue is zero */
        if (err || (p_queue == 0)) {
                lentime = 0;
                goto out;
        }
        err = in_pcbquery_txrtlmt(rack->rc_inp, &p_rate);
        if (err) {
                lentime = 0;
                goto out;
        }
        /*
         * If we reach here we have some bytes in
         * the queue. The number returned is a value
         * between 0 and 0xffff where ffff is full
         * and 0 is empty. So how best to make this into
         * something usable?
         *
         * The "safer" way is lets take the b/w gotten
         * from the query (which should be our b/w rate)
         * and pretend that a full send (our rc_pace_max_segs)
         * is outstanding. We factor it so its as if a full
         * number of our MSS segment is terms of full
         * ethernet segments are outstanding.
         */
        bw = p_rate / 8;
        if (bw) {
                lentime = (rack->r_ctl.rc_pace_max_segs / segsiz);
                lentime *= ETHERNET_SEGMENT_SIZE;
                lentime *= (uint64_t)HPTS_USEC_IN_SEC;
                lentime /= bw;
        } else {
                /* TSNH -- KASSERT? */
                lentime = 0;
        }
out:
        if (tcp_bblogging_on(tp)) {
                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                log.u_bbr.flex1 = p_rate;
                log.u_bbr.flex2 = p_queue;
                log.u_bbr.flex4 = (uint32_t)rack->r_ctl.crte->using;
                log.u_bbr.flex5 = (uint32_t)rack->r_ctl.crte->rs_num_enobufs;
                log.u_bbr.flex6 = rack->r_ctl.crte->time_between;
                log.u_bbr.flex7 = 99;
                log.u_bbr.flex8 = 0;
                log.u_bbr.pkts_out = err;
                log.u_bbr.delRate = rack->r_ctl.crte->rate;
                log.u_bbr.cur_del_rate = lentime;
                log.u_bbr.timeStamp = cts;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                tcp_log_event(tp, NULL, NULL, NULL, BBR_LOG_HDWR_PACE, 0,
                               len, &log, false, NULL, __func__, __LINE__,tv);
        }
#endif
        return ((uint32_t)lentime);
}

static int
rack_fast_rsm_output(struct tcpcb *tp, struct tcp_rack *rack, struct rack_sendmap *rsm,
                     uint64_t ts_val, uint32_t cts, uint32_t ms_cts, struct timeval *tv, int len, uint8_t doing_tlp)
{
        /*
         * Enter the fast retransmit path. We are given that a sched_pin is
         * in place (if accounting is compliled in) and the cycle count taken
         * at the entry is in the ts_val. The concept her is that the rsm
         * now holds the mbuf offsets and such so we can directly transmit
         * without a lot of overhead, the len field is already set for
         * us to prohibit us from sending too much (usually its 1MSS).
         */
        struct ip *ip = NULL;
        struct udphdr *udp = NULL;
        struct tcphdr *th = NULL;
        struct mbuf *m = NULL;
        struct inpcb *inp;
        uint8_t *cpto;
        struct tcp_log_buffer *lgb;
#ifdef TCP_ACCOUNTING
        uint64_t crtsc;
        int cnt_thru = 1;
#endif
        struct tcpopt to;
        u_char opt[TCP_MAXOLEN];
        uint32_t hdrlen, optlen;
        int32_t pacing_delay, segsiz, max_val, tso = 0, error = 0, ulen = 0;
        uint16_t flags;
        uint32_t if_hw_tsomaxsegcount = 0, startseq;
        uint32_t if_hw_tsomaxsegsize;
        int32_t ip_sendflag = IP_NO_SND_TAG_RL;

#ifdef INET6
        struct ip6_hdr *ip6 = NULL;

        if (rack->r_is_v6) {
                ip6 = (struct ip6_hdr *)rack->r_ctl.fsb.tcp_ip_hdr;
                hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
        } else
#endif                          /* INET6 */
        {
                ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr;
                hdrlen = sizeof(struct tcpiphdr);
        }
        if (tp->t_port && (V_tcp_udp_tunneling_port == 0)) {
                goto failed;
        }
        if (doing_tlp) {
                /* Its a TLP add the flag, it may already be there but be sure */
                rsm->r_flags |= RACK_TLP;
        } else {
                /* If it was a TLP it is not not on this retransmit */
                rsm->r_flags &= ~RACK_TLP;
        }
        startseq = rsm->r_start;
        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        inp = rack->rc_inp;
        to.to_flags = 0;
        flags = tcp_outflags[tp->t_state];
        if (flags & (TH_SYN|TH_RST)) {
                goto failed;
        }
        if (rsm->r_flags & RACK_HAS_FIN) {
                /* We can't send a FIN here */
                goto failed;
        }
        if (flags & TH_FIN) {
                /* We never send a FIN */
                flags &= ~TH_FIN;
        }
        if (tp->t_flags & TF_RCVD_TSTMP) {
                to.to_tsval = ms_cts + tp->ts_offset;
                to.to_tsecr = tp->ts_recent;
                to.to_flags = TOF_TS;
        }
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
        /* TCP-MD5 (RFC2385). */
        if (tp->t_flags & TF_SIGNATURE)
                to.to_flags |= TOF_SIGNATURE;
#endif
        optlen = tcp_addoptions(&to, opt);
        hdrlen += optlen;
        udp = rack->r_ctl.fsb.udp;
        if (udp)
                hdrlen += sizeof(struct udphdr);
        if (rack->r_ctl.rc_pace_max_segs)
                max_val = rack->r_ctl.rc_pace_max_segs;
        else if (rack->rc_user_set_max_segs)
                max_val = rack->rc_user_set_max_segs * segsiz;
        else
                max_val = len;
        if ((tp->t_flags & TF_TSO) &&
            V_tcp_do_tso &&
            (len > segsiz) &&
            (tp->t_port == 0))
                tso = 1;
#ifdef INET6
        if (MHLEN < hdrlen + max_linkhdr)
                m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
        else
#endif
                m = m_gethdr(M_NOWAIT, MT_DATA);
        if (m == NULL)
                goto failed;
        m->m_data += max_linkhdr;
        m->m_len = hdrlen;
        th = rack->r_ctl.fsb.th;
        /* Establish the len to send */
        if (len > max_val)
                len = max_val;
        if ((tso) && (len + optlen > segsiz)) {
                uint32_t if_hw_tsomax;
                int32_t max_len;

                /* extract TSO information */
                if_hw_tsomax = tp->t_tsomax;
                if_hw_tsomaxsegcount = tp->t_tsomaxsegcount;
                if_hw_tsomaxsegsize = tp->t_tsomaxsegsize;
                /*
                 * Check if we should limit by maximum payload
                 * length:
                 */
                if (if_hw_tsomax != 0) {
                        /* compute maximum TSO length */
                        max_len = (if_hw_tsomax - hdrlen -
                                   max_linkhdr);
                        if (max_len <= 0) {
                                goto failed;
                        } else if (len > max_len) {
                                len = max_len;
                        }
                }
                if (len <= segsiz) {
                        /*
                         * In case there are too many small fragments don't
                         * use TSO:
                         */
                        tso = 0;
                }
        } else {
                tso = 0;
        }
        if ((tso == 0) && (len > segsiz))
                len = segsiz;
        (void)tcp_get_usecs(tv);
        if ((len == 0) ||
            (len <= MHLEN - hdrlen - max_linkhdr)) {
                goto failed;
        }
        th->th_seq = htonl(rsm->r_start);
        th->th_ack = htonl(tp->rcv_nxt);
        /*
         * The PUSH bit should only be applied
         * if the full retransmission is made. If
         * we are sending less than this is the
         * left hand edge and should not have
         * the PUSH bit.
         */
        if ((rsm->r_flags & RACK_HAD_PUSH) &&
            (len == (rsm->r_end - rsm->r_start)))
                flags |= TH_PUSH;
        th->th_win = htons((u_short)(rack->r_ctl.fsb.recwin >> tp->rcv_scale));
        if (th->th_win == 0) {
                tp->t_sndzerowin++;
                tp->t_flags |= TF_RXWIN0SENT;
        } else
                tp->t_flags &= ~TF_RXWIN0SENT;
        if (rsm->r_flags & RACK_TLP) {
                /*
                 * TLP should not count in retran count, but
                 * in its own bin
                 */
                counter_u64_add(rack_tlp_retran, 1);
                counter_u64_add(rack_tlp_retran_bytes, len);
        } else {
                tp->t_sndrexmitpack++;
                KMOD_TCPSTAT_INC(tcps_sndrexmitpack);
                KMOD_TCPSTAT_ADD(tcps_sndrexmitbyte, len);
        }
#ifdef STATS
        stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_RETXPB,
                                 len);
#endif
        if (rsm->m == NULL)
                goto failed;
        if (rsm->m &&
            ((rsm->orig_m_len != rsm->m->m_len) ||
             (M_TRAILINGROOM(rsm->m) != rsm->orig_t_space))) {
                /* Fix up the orig_m_len and possibly the mbuf offset */
                rack_adjust_orig_mlen(rsm);
        }
        m->m_next = rack_fo_base_copym(rsm->m, rsm->soff, &len, NULL, if_hw_tsomaxsegcount, if_hw_tsomaxsegsize, rsm->r_hw_tls);
        if (len <= segsiz) {
                /*
                 * Must have ran out of mbufs for the copy
                 * shorten it to no longer need tso. Lets
                 * not put on sendalot since we are low on
                 * mbufs.
                 */
                tso = 0;
        }
        if ((m->m_next == NULL) || (len <= 0)){
                goto failed;
        }
        if (udp) {
                if (rack->r_is_v6)
                        ulen = hdrlen + len - sizeof(struct ip6_hdr);
                else
                        ulen = hdrlen + len - sizeof(struct ip);
                udp->uh_ulen = htons(ulen);
        }
        m->m_pkthdr.rcvif = (struct ifnet *)0;
        if (TCPS_HAVERCVDSYN(tp->t_state) &&
            (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT))) {
                int ect = tcp_ecn_output_established(tp, &flags, len, true);
                if ((tp->t_state == TCPS_SYN_RECEIVED) &&
                    (tp->t_flags2 & TF2_ECN_SND_ECE))
                    tp->t_flags2 &= ~TF2_ECN_SND_ECE;
#ifdef INET6
                if (rack->r_is_v6) {
                    ip6->ip6_flow &= ~htonl(IPTOS_ECN_MASK << 20);
                    ip6->ip6_flow |= htonl(ect << 20);
                }
                else
#endif
                {
                    ip->ip_tos &= ~IPTOS_ECN_MASK;
                    ip->ip_tos |= ect;
                }
        }
        if (rack->r_ctl.crte != NULL) {
                /* See if we can send via the hw queue */
                pacing_delay = rack_check_queue_level(rack, tp, tv, cts, len, segsiz);
                /* If there is nothing in queue (no pacing time) we can send via the hw queue */
                if (pacing_delay == 0)
                        ip_sendflag = 0;
        }
        tcp_set_flags(th, flags);
        m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
        if (to.to_flags & TOF_SIGNATURE) {
                /*
                 * Calculate MD5 signature and put it into the place
                 * determined before.
                 * NOTE: since TCP options buffer doesn't point into
                 * mbuf's data, calculate offset and use it.
                 */
                if (!TCPMD5_ENABLED() || TCPMD5_OUTPUT(m, th,
                                                       (u_char *)(th + 1) + (to.to_signature - opt)) != 0) {
                        /*
                         * Do not send segment if the calculation of MD5
                         * digest has failed.
                         */
                        goto failed;
                }
        }
#endif
#ifdef INET6
        if (rack->r_is_v6) {
                if (tp->t_port) {
                        m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
                        m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
                        udp->uh_sum = in6_cksum_pseudo(ip6, ulen, IPPROTO_UDP, 0);
                        th->th_sum = htons(0);
                        UDPSTAT_INC(udps_opackets);
                } else {
                        m->m_pkthdr.csum_flags = CSUM_TCP_IPV6;
                        m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
                        th->th_sum = in6_cksum_pseudo(ip6,
                                                      sizeof(struct tcphdr) + optlen + len, IPPROTO_TCP,
                                                      0);
                }
        }
#endif
#if defined(INET6) && defined(INET)
        else
#endif
#ifdef INET
        {
                if (tp->t_port) {
                        m->m_pkthdr.csum_flags = CSUM_UDP;
                        m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
                        udp->uh_sum = in_pseudo(ip->ip_src.s_addr,
                                                ip->ip_dst.s_addr, htons(ulen + IPPROTO_UDP));
                        th->th_sum = htons(0);
                        UDPSTAT_INC(udps_opackets);
                } else {
                        m->m_pkthdr.csum_flags = CSUM_TCP;
                        m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
                        th->th_sum = in_pseudo(ip->ip_src.s_addr,
                                               ip->ip_dst.s_addr, htons(sizeof(struct tcphdr) +
                                                                        IPPROTO_TCP + len + optlen));
                }
                /* IP version must be set here for ipv4/ipv6 checking later */
                KASSERT(ip->ip_v == IPVERSION,
                        ("%s: IP version incorrect: %d", __func__, ip->ip_v));
        }
#endif
        if (tso) {
                /*
                 * Here we use segsiz since we have no added options besides
                 * any standard timestamp options (no DSACKs or SACKS are sent
                 * via either fast-path).
                 */
                KASSERT(len > segsiz,
                        ("%s: len <= tso_segsz tp:%p", __func__, tp));
                m->m_pkthdr.csum_flags |= CSUM_TSO;
                m->m_pkthdr.tso_segsz = segsiz;
        }
#ifdef INET6
        if (rack->r_is_v6) {
                ip6->ip6_hlim = rack->r_ctl.fsb.hoplimit;
                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
                if (V_path_mtu_discovery && tp->t_maxseg > V_tcp_minmss)
                        tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                else
                        tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
        }
#endif
#if defined(INET) && defined(INET6)
        else
#endif
#ifdef INET
        {
                ip->ip_len = htons(m->m_pkthdr.len);
                ip->ip_ttl = rack->r_ctl.fsb.hoplimit;
                if (V_path_mtu_discovery && tp->t_maxseg > V_tcp_minmss) {
                        tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                        if (tp->t_port == 0 || len < V_tcp_minmss) {
                                ip->ip_off |= htons(IP_DF);
                        }
                } else {
                        tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
                }
        }
#endif
        if (doing_tlp == 0) {
                /* Set we retransmitted */
                rack->rc_gp_saw_rec = 1;
        } else {
                /* Its a TLP set ca or ss */
                if (tp->snd_cwnd > tp->snd_ssthresh) {
                        /* Set we sent in CA */
                        rack->rc_gp_saw_ca = 1;
                } else {
                        /* Set we sent in SS */
                        rack->rc_gp_saw_ss = 1;
                }
        }
        /* Time to copy in our header */
        cpto = mtod(m, uint8_t *);
        memcpy(cpto, rack->r_ctl.fsb.tcp_ip_hdr, rack->r_ctl.fsb.tcp_ip_hdr_len);
        th = (struct tcphdr *)(cpto + ((uint8_t *)rack->r_ctl.fsb.th - rack->r_ctl.fsb.tcp_ip_hdr));
        if (optlen) {
                bcopy(opt, th + 1, optlen);
                th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
        } else {
                th->th_off = sizeof(struct tcphdr) >> 2;
        }
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;

                if (rsm->r_flags & RACK_RWND_COLLAPSED) {
                        rack_log_collapse(rack, rsm->r_start, rsm->r_end, 0, __LINE__, 5, rsm->r_flags, rsm);
                        counter_u64_add(rack_collapsed_win_rxt, 1);
                        counter_u64_add(rack_collapsed_win_rxt_bytes, (rsm->r_end - rsm->r_start));
                }
                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                if (rack->rack_no_prr)
                        log.u_bbr.flex1 = 0;
                else
                        log.u_bbr.flex1 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex2 = rack->r_ctl.rc_pace_min_segs;
                log.u_bbr.flex3 = rack->r_ctl.rc_pace_max_segs;
                log.u_bbr.flex4 = max_val;
                /* Save off the early/late values */
                log.u_bbr.flex6 = rack->r_ctl.rc_agg_early;
                log.u_bbr.applimited = rack->r_ctl.rc_agg_delayed;
                log.u_bbr.bw_inuse = rack_get_bw(rack);
                log.u_bbr.cur_del_rate = rack->r_ctl.gp_bw;
                if (doing_tlp == 0)
                        log.u_bbr.flex8 = 1;
                else
                        log.u_bbr.flex8 = 2;
                log.u_bbr.pacing_gain = rack_get_output_gain(rack, NULL);
                log.u_bbr.flex7 = 55;
                log.u_bbr.pkts_out = tp->t_maxseg;
                log.u_bbr.timeStamp = cts;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                if (rsm->r_rtr_cnt > 0) {
                        /*
                         * When we have a retransmit we want to log the
                         * burst at send and flight at send from before.
                         */
                        log.u_bbr.flex5 = rsm->r_fas;
                        log.u_bbr.bbr_substate = rsm->r_bas;
                } else {
                        /*
                         * This is currently unlikely until we do the
                         * packet pair probes but I will add it for completeness.
                         */
                        log.u_bbr.flex5 = log.u_bbr.inflight;
                        log.u_bbr.bbr_substate = (uint8_t)((len + segsiz - 1)/segsiz);
                }
                log.u_bbr.lt_epoch = rack->r_ctl.cwnd_to_use;
                log.u_bbr.delivered = 0;
                log.u_bbr.rttProp = (uintptr_t)rsm;
                log.u_bbr.delRate = rsm->r_flags;
                log.u_bbr.delRate <<= 31;
                log.u_bbr.delRate |= rack->r_must_retran;
                log.u_bbr.delRate <<= 1;
                log.u_bbr.delRate |= 1;
                log.u_bbr.pkt_epoch = __LINE__;
                lgb = tcp_log_event(tp, th, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK,
                                     len, &log, false, NULL, __func__, __LINE__, tv);
        } else
                lgb = NULL;
        if ((rack->r_ctl.crte != NULL) &&
            tcp_bblogging_on(tp)) {
                rack_log_queue_level(tp, rack, len, tv, cts);
        }
#ifdef INET6
        if (rack->r_is_v6) {
                error = ip6_output(m, inp->in6p_outputopts,
                                   &inp->inp_route6,
                                   ip_sendflag, NULL, NULL, inp);
        }
        else
#endif
#ifdef INET
        {
                error = ip_output(m, NULL,
                                  &inp->inp_route,
                                  ip_sendflag, 0, inp);
        }
#endif
        m = NULL;
        if (lgb) {
                lgb->tlb_errno = error;
                lgb = NULL;
        }
        /* Move snd_nxt to snd_max so we don't have false retransmissions */
        tp->snd_nxt = tp->snd_max;
        if (error) {
                goto failed;
        } else if (rack->rc_hw_nobuf && (ip_sendflag != IP_NO_SND_TAG_RL)) {
                rack->rc_hw_nobuf = 0;
                rack->r_ctl.rc_agg_delayed = 0;
                rack->r_early = 0;
                rack->r_late = 0;
                rack->r_ctl.rc_agg_early = 0;
        }
        rack_log_output(tp, &to, len, rsm->r_start, flags, error, rack_to_usec_ts(tv),
                        rsm, RACK_SENT_FP, rsm->m, rsm->soff, rsm->r_hw_tls, segsiz);
        if (doing_tlp) {
                rack->rc_tlp_in_progress = 1;
                rack->r_ctl.rc_tlp_cnt_out++;
        }
        if (error == 0) {
                counter_u64_add(rack_total_bytes, len);
                tcp_account_for_send(tp, len, 1, doing_tlp, rsm->r_hw_tls);
                if (doing_tlp) {
                        rack->rc_last_sent_tlp_past_cumack = 0;
                        rack->rc_last_sent_tlp_seq_valid = 1;
                        rack->r_ctl.last_sent_tlp_seq = rsm->r_start;
                        rack->r_ctl.last_sent_tlp_len = rsm->r_end - rsm->r_start;
                }
                if (rack->r_ctl.rc_prr_sndcnt >= len)
                        rack->r_ctl.rc_prr_sndcnt -= len;
                else
                        rack->r_ctl.rc_prr_sndcnt = 0;
        }
        tp->t_flags &= ~(TF_ACKNOW | TF_DELACK);
        rack->forced_ack = 0;   /* If we send something zap the FA flag */
        if (IN_FASTRECOVERY(tp->t_flags) && rsm)
                rack->r_ctl.retran_during_recovery += len;
        {
                int idx;

                idx = (len / segsiz) + 3;
                if (idx >= TCP_MSS_ACCT_ATIMER)
                        counter_u64_add(rack_out_size[(TCP_MSS_ACCT_ATIMER-1)], 1);
                else
                        counter_u64_add(rack_out_size[idx], 1);
        }
        if (tp->t_rtttime == 0) {
                tp->t_rtttime = ticks;
                tp->t_rtseq = startseq;
                KMOD_TCPSTAT_INC(tcps_segstimed);
        }
        counter_u64_add(rack_fto_rsm_send, 1);
        if (error && (error == ENOBUFS)) {
                if (rack->r_ctl.crte != NULL) {
                        tcp_trace_point(rack->rc_tp, TCP_TP_HWENOBUF);
                        if (tcp_bblogging_on(rack->rc_tp))
                                rack_log_queue_level(tp, rack, len, tv, cts);
                } else
                        tcp_trace_point(rack->rc_tp, TCP_TP_ENOBUF);
                pacing_delay = ((1 + rack->rc_enobuf) * HPTS_USEC_IN_MSEC);
                if (rack->rc_enobuf < 0x7f)
                        rack->rc_enobuf++;
                if (pacing_delay < (10 * HPTS_USEC_IN_MSEC))
                        pacing_delay = 10 * HPTS_USEC_IN_MSEC;
                if (rack->r_ctl.crte != NULL) {
                        counter_u64_add(rack_saw_enobuf_hw, 1);
                        tcp_rl_log_enobuf(rack->r_ctl.crte);
                }
                counter_u64_add(rack_saw_enobuf, 1);
        } else {
                pacing_delay = rack_get_pacing_delay(rack, tp, len, NULL, segsiz, __LINE__);
        }
        rack_start_hpts_timer(rack, tp, cts, pacing_delay, len, 0);
#ifdef TCP_ACCOUNTING
        crtsc = get_cyclecount();
        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                tp->tcp_cnt_counters[SND_OUT_DATA] += cnt_thru;
                tp->tcp_proc_time[SND_OUT_DATA] += (crtsc - ts_val);
                tp->tcp_cnt_counters[CNT_OF_MSS_OUT] += ((len + segsiz - 1) / segsiz);
        }
        sched_unpin();
#endif
        return (0);
failed:
        if (m)
                m_free(m);
        return (-1);
}

static void
rack_sndbuf_autoscale(struct tcp_rack *rack)
{
        /*
         * Automatic sizing of send socket buffer.  Often the send buffer
         * size is not optimally adjusted to the actual network conditions
         * at hand (delay bandwidth product).  Setting the buffer size too
         * small limits throughput on links with high bandwidth and high
         * delay (eg. trans-continental/oceanic links).  Setting the
         * buffer size too big consumes too much real kernel memory,
         * especially with many connections on busy servers.
         *
         * The criteria to step up the send buffer one notch are:
         *  1. receive window of remote host is larger than send buffer
         *     (with a fudge factor of 5/4th);
         *  2. send buffer is filled to 7/8th with data (so we actually
         *     have data to make use of it);
         *  3. send buffer fill has not hit maximal automatic size;
         *  4. our send window (slow start and cogestion controlled) is
         *     larger than sent but unacknowledged data in send buffer.
         *
         * Note that the rack version moves things much faster since
         * we want to avoid hitting cache lines in the rack_fast_output()
         * path so this is called much less often and thus moves
         * the SB forward by a percentage.
         */
        struct socket *so;
        struct tcpcb *tp;
        uint32_t sendwin, scaleup;

        tp = rack->rc_tp;
        so = rack->rc_inp->inp_socket;
        sendwin = min(rack->r_ctl.cwnd_to_use, tp->snd_wnd);
        if (V_tcp_do_autosndbuf && so->so_snd.sb_flags & SB_AUTOSIZE) {
                if ((tp->snd_wnd / 4 * 5) >= so->so_snd.sb_hiwat &&
                    sbused(&so->so_snd) >=
                    (so->so_snd.sb_hiwat / 8 * 7) &&
                    sbused(&so->so_snd) < V_tcp_autosndbuf_max &&
                    sendwin >= (sbused(&so->so_snd) -
                    (tp->snd_max - tp->snd_una))) {
                        if (rack_autosndbuf_inc)
                                scaleup = (rack_autosndbuf_inc * so->so_snd.sb_hiwat) / 100;
                        else
                                scaleup = V_tcp_autosndbuf_inc;
                        if (scaleup < V_tcp_autosndbuf_inc)
                                scaleup = V_tcp_autosndbuf_inc;
                        scaleup += so->so_snd.sb_hiwat;
                        if (scaleup > V_tcp_autosndbuf_max)
                                scaleup = V_tcp_autosndbuf_max;
                        if (!sbreserve_locked(so, SO_SND, scaleup, curthread))
                                so->so_snd.sb_flags &= ~SB_AUTOSIZE;
                }
        }
}

static int
rack_fast_output(struct tcpcb *tp, struct tcp_rack *rack, uint64_t ts_val,
                 uint32_t cts, uint32_t ms_cts, struct timeval *tv, long *tot_len, int *send_err, int line)
{
        /*
         * Enter to do fast output. We are given that the sched_pin is
         * in place (if accounting is compiled in) and the cycle count taken
         * at entry is in place in ts_val. The idea here is that
         * we know how many more bytes needs to be sent (presumably either
         * during pacing or to fill the cwnd and that was greater than
         * the max-burst). We have how much to send and all the info we
         * need to just send.
         */
#ifdef INET
        struct ip *ip = NULL;
#endif
        struct udphdr *udp = NULL;
        struct tcphdr *th = NULL;
        struct mbuf *m, *s_mb;
        struct inpcb *inp;
        uint8_t *cpto;
        struct tcp_log_buffer *lgb;
#ifdef TCP_ACCOUNTING
        uint64_t crtsc;
#endif
        struct tcpopt to;
        u_char opt[TCP_MAXOLEN];
        uint32_t hdrlen, optlen;
#ifdef TCP_ACCOUNTING
        int cnt_thru = 1;
#endif
        int32_t pacing_delay, segsiz, len, max_val, tso = 0, sb_offset, error, ulen = 0;
        uint16_t flags;
        uint32_t s_soff;
        uint32_t if_hw_tsomaxsegcount = 0, startseq;
        uint32_t if_hw_tsomaxsegsize;
        uint32_t add_flag = RACK_SENT_FP;
#ifdef INET6
        struct ip6_hdr *ip6 = NULL;

        if (rack->r_is_v6) {
                ip6 = (struct ip6_hdr *)rack->r_ctl.fsb.tcp_ip_hdr;
                hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
        } else
#endif                          /* INET6 */
        {
#ifdef INET
                ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr;
                hdrlen = sizeof(struct tcpiphdr);
#endif
        }
        if (tp->t_port && (V_tcp_udp_tunneling_port == 0)) {
                m = NULL;
                goto failed;
        }
        rack->r_ctl.cwnd_to_use = tp->snd_cwnd;
        startseq = tp->snd_max;
        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        inp = rack->rc_inp;
        len = rack->r_ctl.fsb.left_to_send;
        to.to_flags = 0;
        flags = rack->r_ctl.fsb.tcp_flags;
        if (tp->t_flags & TF_RCVD_TSTMP) {
                to.to_tsval = ms_cts + tp->ts_offset;
                to.to_tsecr = tp->ts_recent;
                to.to_flags = TOF_TS;
        }
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
        /* TCP-MD5 (RFC2385). */
        if (tp->t_flags & TF_SIGNATURE)
                to.to_flags |= TOF_SIGNATURE;
#endif
        optlen = tcp_addoptions(&to, opt);
        hdrlen += optlen;
        udp = rack->r_ctl.fsb.udp;
        if (udp)
                hdrlen += sizeof(struct udphdr);
        if (rack->r_ctl.rc_pace_max_segs)
                max_val = rack->r_ctl.rc_pace_max_segs;
        else if (rack->rc_user_set_max_segs)
                max_val = rack->rc_user_set_max_segs * segsiz;
        else
                max_val = len;
        if ((tp->t_flags & TF_TSO) &&
            V_tcp_do_tso &&
            (len > segsiz) &&
            (tp->t_port == 0))
                tso = 1;
again:
#ifdef INET6
        if (MHLEN < hdrlen + max_linkhdr)
                m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
        else
#endif
                m = m_gethdr(M_NOWAIT, MT_DATA);
        if (m == NULL)
                goto failed;
        m->m_data += max_linkhdr;
        m->m_len = hdrlen;
        th = rack->r_ctl.fsb.th;
        /* Establish the len to send */
        if (len > max_val)
                len = max_val;
        if ((tso) && (len + optlen > segsiz)) {
                uint32_t if_hw_tsomax;
                int32_t max_len;

                /* extract TSO information */
                if_hw_tsomax = tp->t_tsomax;
                if_hw_tsomaxsegcount = tp->t_tsomaxsegcount;
                if_hw_tsomaxsegsize = tp->t_tsomaxsegsize;
                /*
                 * Check if we should limit by maximum payload
                 * length:
                 */
                if (if_hw_tsomax != 0) {
                        /* compute maximum TSO length */
                        max_len = (if_hw_tsomax - hdrlen -
                                   max_linkhdr);
                        if (max_len <= 0) {
                                goto failed;
                        } else if (len > max_len) {
                                len = max_len;
                        }
                }
                if (len <= segsiz) {
                        /*
                         * In case there are too many small fragments don't
                         * use TSO:
                         */
                        tso = 0;
                }
        } else {
                tso = 0;
        }
        if ((tso == 0) && (len > segsiz))
                len = segsiz;
        (void)tcp_get_usecs(tv);
        if ((len == 0) ||
            (len <= MHLEN - hdrlen - max_linkhdr)) {
                goto failed;
        }
        sb_offset = tp->snd_max - tp->snd_una;
        th->th_seq = htonl(tp->snd_max);
        th->th_ack = htonl(tp->rcv_nxt);
        th->th_win = htons((u_short)(rack->r_ctl.fsb.recwin >> tp->rcv_scale));
        if (th->th_win == 0) {
                tp->t_sndzerowin++;
                tp->t_flags |= TF_RXWIN0SENT;
        } else
                tp->t_flags &= ~TF_RXWIN0SENT;
        tp->snd_up = tp->snd_una;       /* drag it along, its deprecated */
        KMOD_TCPSTAT_INC(tcps_sndpack);
        KMOD_TCPSTAT_ADD(tcps_sndbyte, len);
#ifdef STATS
        stats_voi_update_abs_u64(tp->t_stats, VOI_TCP_TXPB,
                                 len);
#endif
        if (rack->r_ctl.fsb.m == NULL)
                goto failed;

        /* s_mb and s_soff are saved for rack_log_output */
        m->m_next = rack_fo_m_copym(rack, &len, if_hw_tsomaxsegcount, if_hw_tsomaxsegsize,
                                    &s_mb, &s_soff);
        if (len <= segsiz) {
                /*
                 * Must have ran out of mbufs for the copy
                 * shorten it to no longer need tso. Lets
                 * not put on sendalot since we are low on
                 * mbufs.
                 */
                tso = 0;
        }
        if (rack->r_ctl.fsb.rfo_apply_push &&
            (len == rack->r_ctl.fsb.left_to_send)) {
                flags |= TH_PUSH;
                add_flag |= RACK_HAD_PUSH;
        }
        if ((m->m_next == NULL) || (len <= 0)){
                goto failed;
        }
        if (udp) {
                if (rack->r_is_v6)
                        ulen = hdrlen + len - sizeof(struct ip6_hdr);
                else
                        ulen = hdrlen + len - sizeof(struct ip);
                udp->uh_ulen = htons(ulen);
        }
        m->m_pkthdr.rcvif = (struct ifnet *)0;
        if (TCPS_HAVERCVDSYN(tp->t_state) &&
            (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT))) {
                int ect = tcp_ecn_output_established(tp, &flags, len, false);
                if ((tp->t_state == TCPS_SYN_RECEIVED) &&
                    (tp->t_flags2 & TF2_ECN_SND_ECE))
                        tp->t_flags2 &= ~TF2_ECN_SND_ECE;
#ifdef INET6
                if (rack->r_is_v6) {
                        ip6->ip6_flow &= ~htonl(IPTOS_ECN_MASK << 20);
                        ip6->ip6_flow |= htonl(ect << 20);
                }
                else
#endif
                {
#ifdef INET
                        ip->ip_tos &= ~IPTOS_ECN_MASK;
                        ip->ip_tos |= ect;
#endif
                }
        }
        tcp_set_flags(th, flags);
        m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
        if (to.to_flags & TOF_SIGNATURE) {
                /*
                 * Calculate MD5 signature and put it into the place
                 * determined before.
                 * NOTE: since TCP options buffer doesn't point into
                 * mbuf's data, calculate offset and use it.
                 */
                if (!TCPMD5_ENABLED() || TCPMD5_OUTPUT(m, th,
                                                       (u_char *)(th + 1) + (to.to_signature - opt)) != 0) {
                        /*
                         * Do not send segment if the calculation of MD5
                         * digest has failed.
                         */
                        goto failed;
                }
        }
#endif
#ifdef INET6
        if (rack->r_is_v6) {
                if (tp->t_port) {
                        m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
                        m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
                        udp->uh_sum = in6_cksum_pseudo(ip6, ulen, IPPROTO_UDP, 0);
                        th->th_sum = htons(0);
                        UDPSTAT_INC(udps_opackets);
                } else {
                        m->m_pkthdr.csum_flags = CSUM_TCP_IPV6;
                        m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
                        th->th_sum = in6_cksum_pseudo(ip6,
                                                      sizeof(struct tcphdr) + optlen + len, IPPROTO_TCP,
                                                      0);
                }
        }
#endif
#if defined(INET6) && defined(INET)
        else
#endif
#ifdef INET
        {
                if (tp->t_port) {
                        m->m_pkthdr.csum_flags = CSUM_UDP;
                        m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
                        udp->uh_sum = in_pseudo(ip->ip_src.s_addr,
                                                ip->ip_dst.s_addr, htons(ulen + IPPROTO_UDP));
                        th->th_sum = htons(0);
                        UDPSTAT_INC(udps_opackets);
                } else {
                        m->m_pkthdr.csum_flags = CSUM_TCP;
                        m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
                        th->th_sum = in_pseudo(ip->ip_src.s_addr,
                                               ip->ip_dst.s_addr, htons(sizeof(struct tcphdr) +
                                                                        IPPROTO_TCP + len + optlen));
                }
                /* IP version must be set here for ipv4/ipv6 checking later */
                KASSERT(ip->ip_v == IPVERSION,
                        ("%s: IP version incorrect: %d", __func__, ip->ip_v));
        }
#endif
        if (tso) {
                /*
                 * Here we use segsiz since we have no added options besides
                 * any standard timestamp options (no DSACKs or SACKS are sent
                 * via either fast-path).
                 */
                KASSERT(len > segsiz,
                        ("%s: len <= tso_segsz tp:%p", __func__, tp));
                m->m_pkthdr.csum_flags |= CSUM_TSO;
                m->m_pkthdr.tso_segsz = segsiz;
        }
#ifdef INET6
        if (rack->r_is_v6) {
                ip6->ip6_hlim = rack->r_ctl.fsb.hoplimit;
                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
                if (V_path_mtu_discovery && tp->t_maxseg > V_tcp_minmss)
                        tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                else
                        tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
        }
#endif
#if defined(INET) && defined(INET6)
        else
#endif
#ifdef INET
        {
                ip->ip_len = htons(m->m_pkthdr.len);
                ip->ip_ttl = rack->r_ctl.fsb.hoplimit;
                if (V_path_mtu_discovery && tp->t_maxseg > V_tcp_minmss) {
                        tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                        if (tp->t_port == 0 || len < V_tcp_minmss) {
                                ip->ip_off |= htons(IP_DF);
                        }
                } else {
                        tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
                }
        }
#endif
        if (tp->snd_cwnd > tp->snd_ssthresh) {
                /* Set we sent in CA */
                rack->rc_gp_saw_ca = 1;
        } else {
                /* Set we sent in SS */
                rack->rc_gp_saw_ss = 1;
        }
        /* Time to copy in our header */
        cpto = mtod(m, uint8_t *);
        memcpy(cpto, rack->r_ctl.fsb.tcp_ip_hdr, rack->r_ctl.fsb.tcp_ip_hdr_len);
        th = (struct tcphdr *)(cpto + ((uint8_t *)rack->r_ctl.fsb.th - rack->r_ctl.fsb.tcp_ip_hdr));
        if (optlen) {
                bcopy(opt, th + 1, optlen);
                th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
        } else {
                th->th_off = sizeof(struct tcphdr) >> 2;
        }
        if ((rack->r_ctl.crte != NULL) &&
            tcp_bblogging_on(tp)) {
                rack_log_queue_level(tp, rack, len, tv, cts);
        }
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                if (rack->rack_no_prr)
                        log.u_bbr.flex1 = 0;
                else
                        log.u_bbr.flex1 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex2 = rack->r_ctl.rc_pace_min_segs;
                log.u_bbr.flex3 = rack->r_ctl.rc_pace_max_segs;
                log.u_bbr.flex4 = max_val;
                /* Save off the early/late values */
                log.u_bbr.flex6 = rack->r_ctl.rc_agg_early;
                log.u_bbr.applimited = rack->r_ctl.rc_agg_delayed;
                log.u_bbr.bw_inuse = rack_get_bw(rack);
                log.u_bbr.cur_del_rate = rack->r_ctl.gp_bw;
                log.u_bbr.flex8 = 0;
                log.u_bbr.pacing_gain = rack_get_output_gain(rack, NULL);
                log.u_bbr.flex7 = 44;
                log.u_bbr.pkts_out = tp->t_maxseg;
                log.u_bbr.timeStamp = cts;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                log.u_bbr.flex5 = log.u_bbr.inflight;
                log.u_bbr.lt_epoch = rack->r_ctl.cwnd_to_use;
                log.u_bbr.delivered = rack->r_ctl.fsb.left_to_send;
                log.u_bbr.rttProp = 0;
                log.u_bbr.delRate = rack->r_must_retran;
                log.u_bbr.delRate <<= 1;
                log.u_bbr.pkt_epoch = line;
                /* For fast output no retrans so just inflight and how many mss we send */
                log.u_bbr.flex5 = log.u_bbr.inflight;
                log.u_bbr.bbr_substate = (uint8_t)((len + segsiz - 1)/segsiz);
                lgb = tcp_log_event(tp, th, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK,
                                     len, &log, false, NULL, __func__, __LINE__, tv);
        } else
                lgb = NULL;
#ifdef INET6
        if (rack->r_is_v6) {
                error = ip6_output(m, inp->in6p_outputopts,
                                   &inp->inp_route6,
                                   0, NULL, NULL, inp);
        }
#endif
#if defined(INET) && defined(INET6)
        else
#endif
#ifdef INET
        {
                error = ip_output(m, NULL,
                                  &inp->inp_route,
                                  0, 0, inp);
        }
#endif
        if (lgb) {
                lgb->tlb_errno = error;
                lgb = NULL;
        }
        if (error) {
                *send_err = error;
                m = NULL;
                goto failed;
        } else if (rack->rc_hw_nobuf) {
                rack->rc_hw_nobuf = 0;
                rack->r_ctl.rc_agg_delayed = 0;
                rack->r_early = 0;
                rack->r_late = 0;
                rack->r_ctl.rc_agg_early = 0;
        }
        if ((error == 0) && (rack->lt_bw_up == 0)) {
                /* Unlikely */
                rack->r_ctl.lt_timemark = tcp_tv_to_lusec(tv);
                rack->r_ctl.lt_seq = tp->snd_una;
                rack->lt_bw_up = 1;
        } else if ((error == 0) &&
                   (((tp->snd_max + len) - rack->r_ctl.lt_seq) > 0x7fffffff)) {
                /*
                 * Need to record what we have since we are
                 * approaching seq wrap.
                 */
                struct timeval tv;
                uint64_t tmark;

                rack->r_ctl.lt_bw_bytes += (tp->snd_una - rack->r_ctl.lt_seq);
                rack->r_ctl.lt_seq = tp->snd_una;
                tmark = tcp_get_u64_usecs(&tv);
                if (tmark > rack->r_ctl.lt_timemark) {
                        rack->r_ctl.lt_bw_time += (tmark - rack->r_ctl.lt_timemark);
                        rack->r_ctl.lt_timemark = tmark;
                }
        }
        rack_log_output(tp, &to, len, tp->snd_max, flags, error, rack_to_usec_ts(tv),
                        NULL, add_flag, s_mb, s_soff, rack->r_ctl.fsb.hw_tls, segsiz);
        if (tp->snd_una == tp->snd_max) {
                rack->r_ctl.rc_tlp_rxt_last_time = cts;
                rack_log_progress_event(rack, tp, ticks, PROGRESS_START, __LINE__);
                tp->t_acktime = ticks;
        }
        counter_u64_add(rack_total_bytes, len);
        tcp_account_for_send(tp, len, 0, 0, rack->r_ctl.fsb.hw_tls);

        rack->forced_ack = 0;   /* If we send something zap the FA flag */
        *tot_len += len;
        if ((tp->t_flags & TF_GPUTINPROG) == 0)
                rack_start_gp_measurement(tp, rack, tp->snd_max, sb_offset);
        tp->snd_max += len;
        tp->snd_nxt = tp->snd_max;
        if (rack->rc_new_rnd_needed) {
                rack_new_round_starts(tp, rack, tp->snd_max);
        }
        {
                int idx;

                idx = (len / segsiz) + 3;
                if (idx >= TCP_MSS_ACCT_ATIMER)
                        counter_u64_add(rack_out_size[(TCP_MSS_ACCT_ATIMER-1)], 1);
                else
                        counter_u64_add(rack_out_size[idx], 1);
        }
        if (len <= rack->r_ctl.fsb.left_to_send)
                rack->r_ctl.fsb.left_to_send -= len;
        else
                rack->r_ctl.fsb.left_to_send = 0;
        if (rack->r_ctl.fsb.left_to_send < segsiz) {
                rack->r_fast_output = 0;
                rack->r_ctl.fsb.left_to_send = 0;
                /* At the end of fast_output scale up the sb */
                SOCK_SENDBUF_LOCK(rack->rc_inp->inp_socket);
                rack_sndbuf_autoscale(rack);
                SOCK_SENDBUF_UNLOCK(rack->rc_inp->inp_socket);
        }
        if (tp->t_rtttime == 0) {
                tp->t_rtttime = ticks;
                tp->t_rtseq = startseq;
                KMOD_TCPSTAT_INC(tcps_segstimed);
        }
        if ((rack->r_ctl.fsb.left_to_send >= segsiz) &&
            (max_val > len) &&
            (*tot_len < rack->r_ctl.rc_pace_max_segs) &&
            (tso == 0)) {
                max_val -= len;
                len = segsiz;
                th = rack->r_ctl.fsb.th;
#ifdef TCP_ACCOUNTING
                cnt_thru++;
#endif
                goto again;
        }
        tp->t_flags &= ~(TF_ACKNOW | TF_DELACK);
        counter_u64_add(rack_fto_send, 1);
        pacing_delay = rack_get_pacing_delay(rack, tp, *tot_len, NULL, segsiz, __LINE__);
        rack_start_hpts_timer(rack, tp, cts, pacing_delay, *tot_len, 0);
#ifdef TCP_ACCOUNTING
        crtsc = get_cyclecount();
        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                tp->tcp_cnt_counters[SND_OUT_DATA] += cnt_thru;
                tp->tcp_proc_time[SND_OUT_DATA] += (crtsc - ts_val);
                tp->tcp_cnt_counters[CNT_OF_MSS_OUT] += ((*tot_len + segsiz - 1) / segsiz);
        }
        sched_unpin();
#endif
        return (0);
failed:
        if (m)
                m_free(m);
        rack->r_fast_output = 0;
        return (-1);
}

static inline void
rack_setup_fast_output(struct tcpcb *tp, struct tcp_rack *rack,
                       struct sockbuf *sb,
                       int len, int orig_len, int segsiz, uint32_t pace_max_seg,
                       bool hw_tls,
                       uint16_t flags)
{
        rack->r_fast_output = 1;
        rack->r_ctl.fsb.m = sbsndmbuf(sb, (tp->snd_max - tp->snd_una), &rack->r_ctl.fsb.off);
        rack->r_ctl.fsb.o_m_len = rack->r_ctl.fsb.m->m_len;
        rack->r_ctl.fsb.o_t_len = M_TRAILINGROOM(rack->r_ctl.fsb.m);
        rack->r_ctl.fsb.tcp_flags = flags;
        rack->r_ctl.fsb.left_to_send = orig_len - len;
        if (rack->r_ctl.fsb.left_to_send < pace_max_seg) {
                /* Less than a full sized pace, lets not  */
                rack->r_fast_output = 0;
                return;
        } else {
                /* Round down to the nearest pace_max_seg */
                rack->r_ctl.fsb.left_to_send = rounddown(rack->r_ctl.fsb.left_to_send, pace_max_seg);
        }
        if (hw_tls)
                rack->r_ctl.fsb.hw_tls = 1;
        else
                rack->r_ctl.fsb.hw_tls = 0;
        KASSERT((rack->r_ctl.fsb.left_to_send <= (sbavail(sb) - (tp->snd_max - tp->snd_una))),
                ("rack:%p left_to_send:%u sbavail:%u out:%u",
                 rack, rack->r_ctl.fsb.left_to_send, sbavail(sb),
                 (tp->snd_max - tp->snd_una)));
        if (rack->r_ctl.fsb.left_to_send < segsiz)
                rack->r_fast_output = 0;
        else {
                if (rack->r_ctl.fsb.left_to_send == (sbavail(sb) - (tp->snd_max - tp->snd_una)))
                        rack->r_ctl.fsb.rfo_apply_push = 1;
                else
                        rack->r_ctl.fsb.rfo_apply_push = 0;
        }
}

static uint32_t
rack_get_hpts_pacing_min_for_bw(struct tcp_rack *rack, int32_t segsiz)
{
        uint64_t min_time;
        uint32_t maxlen;

        min_time = (uint64_t)get_hpts_min_sleep_time();
        maxlen = (uint32_t)((rack->r_ctl.gp_bw * min_time) / (uint64_t)HPTS_USEC_IN_SEC);
        maxlen = roundup(maxlen, segsiz);
        return (maxlen);
}

static struct rack_sendmap *
rack_check_collapsed(struct tcp_rack *rack, uint32_t cts)
{
        struct rack_sendmap *rsm = NULL;
        int thresh;

restart:
        rsm = tqhash_find(rack->r_ctl.tqh, rack->r_ctl.last_collapse_point);
        if ((rsm == NULL) || ((rsm->r_flags & RACK_RWND_COLLAPSED) == 0)) {
                /* Nothing, strange turn off validity  */
                rack->r_collapse_point_valid = 0;
                return (NULL);
        }
        /* Can we send it yet? */
        if (rsm->r_end > (rack->rc_tp->snd_una + rack->rc_tp->snd_wnd)) {
                /*
                 * Receiver window has not grown enough for
                 * the segment to be put on the wire.
                 */
                return (NULL);
        }
        if (rsm->r_flags & RACK_ACKED) {
                /*
                 * It has been sacked, lets move to the
                 * next one if possible.
                 */
                rack->r_ctl.last_collapse_point = rsm->r_end;
                /* Are we done? */
                if (SEQ_GEQ(rack->r_ctl.last_collapse_point,
                            rack->r_ctl.high_collapse_point)) {
                        rack->r_collapse_point_valid = 0;
                        return (NULL);
                }
                goto restart;
        }
        /* Now has it been long enough ? */
        thresh = rack_calc_thresh_rack(rack, rack_grab_rtt(rack->rc_tp, rack), cts, __LINE__, 1);
        if ((cts - ((uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)])) > thresh) {
                rack_log_collapse(rack, rsm->r_start,
                                  (cts - ((uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)])),
                                  thresh, __LINE__, 6, rsm->r_flags, rsm);
                return (rsm);
        }
        /* Not enough time */
        rack_log_collapse(rack, rsm->r_start,
                          (cts - ((uint32_t)rsm->r_tim_lastsent[(rsm->r_rtr_cnt-1)])),
                          thresh, __LINE__, 7, rsm->r_flags, rsm);
        return (NULL);
}

static inline void
rack_validate_sizes(struct tcp_rack *rack, int32_t *len, int32_t segsiz, uint32_t pace_max_seg)
{
        if ((rack->full_size_rxt == 0) &&
            (rack->shape_rxt_to_pacing_min == 0) &&
            (*len >= segsiz)) {
                *len = segsiz;
        } else if (rack->shape_rxt_to_pacing_min &&
                 rack->gp_ready) {
                /* We use pacing min as shaping len req */
                uint32_t maxlen;

                maxlen = rack_get_hpts_pacing_min_for_bw(rack, segsiz);
                if (*len > maxlen)
                        *len = maxlen;
        } else {
                /*
                 * The else is full_size_rxt is on so send it all
                 * note we do need to check this for exceeding
                 * our max segment size due to the fact that
                 * we do sometimes merge chunks together i.e.
                 * we cannot just assume that we will never have
                 * a chunk greater than pace_max_seg
                 */
                if (*len > pace_max_seg)
                        *len = pace_max_seg;
        }
}

static int
rack_output(struct tcpcb *tp)
{
        struct socket *so;
        uint32_t recwin;
        uint32_t sb_offset, s_moff = 0;
        int32_t len, error = 0;
        uint16_t flags;
        struct mbuf *m, *s_mb = NULL;
        struct mbuf *mb;
        uint32_t if_hw_tsomaxsegcount = 0;
        uint32_t if_hw_tsomaxsegsize;
        int32_t segsiz, minseg;
        long tot_len_this_send = 0;
#ifdef INET
        struct ip *ip = NULL;
#endif
        struct udphdr *udp = NULL;
        struct tcp_rack *rack;
        struct tcphdr *th;
        uint8_t pass = 0;
        uint8_t mark = 0;
        uint8_t check_done = 0;
        uint8_t wanted_cookie = 0;
        u_char opt[TCP_MAXOLEN];
        unsigned ipoptlen, optlen, hdrlen, ulen=0;
        uint32_t rack_seq;

#if defined(IPSEC) || defined(IPSEC_SUPPORT)
        unsigned ipsec_optlen = 0;

#endif
        int32_t idle, sendalot;
        uint32_t tot_idle;
        int32_t sub_from_prr = 0;
        volatile int32_t sack_rxmit;
        struct rack_sendmap *rsm = NULL;
        int32_t tso, mtu;
        struct tcpopt to;
        int32_t pacing_delay = 0;
        int32_t sup_rack = 0;
        uint32_t cts, ms_cts, delayed, early;
        uint32_t add_flag = RACK_SENT_SP;
        /* The doing_tlp flag will be set by the actual rack_timeout_tlp() */
        uint8_t doing_tlp = 0;
        uint32_t cwnd_to_use, pace_max_seg;
        int32_t do_a_prefetch = 0;
        int32_t prefetch_rsm = 0;
        int32_t orig_len = 0;
        struct timeval tv;
        int32_t prefetch_so_done = 0;
        struct tcp_log_buffer *lgb;
        struct inpcb *inp = tptoinpcb(tp);
        struct sockbuf *sb;
        uint64_t ts_val = 0;
#ifdef TCP_ACCOUNTING
        uint64_t crtsc;
#endif
#ifdef INET6
        struct ip6_hdr *ip6 = NULL;
        int32_t isipv6;
#endif
        bool hpts_calling, hw_tls = false;

        NET_EPOCH_ASSERT();
        INP_WLOCK_ASSERT(inp);

        /* setup and take the cache hits here */
        rack = (struct tcp_rack *)tp->t_fb_ptr;
#ifdef TCP_ACCOUNTING
        sched_pin();
        ts_val = get_cyclecount();
#endif
        hpts_calling = !!(tp->t_flags2 & TF2_HPTS_CALLS);
        tp->t_flags2 &= ~TF2_HPTS_CALLS;
#ifdef TCP_OFFLOAD
        if (tp->t_flags & TF_TOE) {
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                return (tcp_offload_output(tp));
        }
#endif
        if (rack->rack_deferred_inited == 0) {
                /*
                 * If we are the connecting socket we will
                 * hit rack_init() when no sequence numbers
                 * are setup. This makes it so we must defer
                 * some initialization. Call that now.
                 */
                rack_deferred_init(tp, rack);
        }
        /*
         * For TFO connections in SYN_RECEIVED, only allow the initial
         * SYN|ACK and those sent by the retransmit timer.
         */
        if ((tp->t_flags & TF_FASTOPEN) &&
            (tp->t_state == TCPS_SYN_RECEIVED) &&
            SEQ_GT(tp->snd_max, tp->snd_una) &&    /* initial SYN|ACK sent */
            (rack->r_ctl.rc_resend == NULL)) {         /* not a retransmit */
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                return (0);
        }
#ifdef INET6
        if (rack->r_state) {
                /* Use the cache line loaded if possible */
                isipv6 = rack->r_is_v6;
        } else {
                isipv6 = (rack->rc_inp->inp_vflag & INP_IPV6) != 0;
        }
#endif
        early = 0;
        cts = tcp_get_usecs(&tv);
        ms_cts = tcp_tv_to_msec(&tv);
        if (((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) == 0) &&
            tcp_in_hpts(rack->rc_tp)) {
                /*
                 * We are on the hpts for some timer but not hptsi output.
                 * Remove from the hpts unconditionally.
                 */
                rack_timer_cancel(tp, rack, cts, __LINE__);
        }
        /* Are we pacing and late? */
        if ((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) &&
            TSTMP_GEQ(cts, rack->r_ctl.rc_last_output_to)) {
                /* We are delayed */
                delayed = cts - rack->r_ctl.rc_last_output_to;
        } else {
                delayed = 0;
        }
        /* Do the timers, which may override the pacer */
        if (rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK) {
                int retval;

                retval = rack_process_timers(tp, rack, cts, hpts_calling,
                                             &doing_tlp);
                if (retval != 0) {
                        counter_u64_add(rack_out_size[TCP_MSS_ACCT_ATIMER], 1);
#ifdef TCP_ACCOUNTING
                        sched_unpin();
#endif
                        /*
                         * If timers want tcp_drop(), then pass error out,
                         * otherwise suppress it.
                         */
                        return (retval < 0 ? retval : 0);
                }
        }
        if (rack->rc_in_persist) {
                if (tcp_in_hpts(rack->rc_tp) == 0) {
                        /* Timer is not running */
                        rack_start_hpts_timer(rack, tp, cts, 0, 0, 0);
                }
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                return (0);
        }
        if ((rack->rc_ack_required == 1) &&
            (rack->r_timer_override == 0)){
                /* A timeout occurred and no ack has arrived */
                if (tcp_in_hpts(rack->rc_tp) == 0) {
                        /* Timer is not running */
                        rack_start_hpts_timer(rack, tp, cts, 0, 0, 0);
                }
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                return (0);
        }
        if ((rack->r_timer_override) ||
            (rack->rc_ack_can_sendout_data) ||
            (delayed) ||
            (tp->t_state < TCPS_ESTABLISHED)) {
                rack->rc_ack_can_sendout_data = 0;
                if (tcp_in_hpts(rack->rc_tp))
                        tcp_hpts_remove(rack->rc_tp);
        } else if (tcp_in_hpts(rack->rc_tp)) {
                /*
                 * On the hpts you can't pass even if ACKNOW is on, we will
                 * when the hpts fires.
                 */
#ifdef TCP_ACCOUNTING
                crtsc = get_cyclecount();
                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                        tp->tcp_proc_time[SND_BLOCKED] += (crtsc - ts_val);
                        tp->tcp_cnt_counters[SND_BLOCKED]++;
                }
                sched_unpin();
#endif
                counter_u64_add(rack_out_size[TCP_MSS_ACCT_INPACE], 1);
                return (0);
        }
        /* Finish out both pacing early and late accounting */
        if ((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) &&
            TSTMP_GT(rack->r_ctl.rc_last_output_to, cts)) {
                early = rack->r_ctl.rc_last_output_to - cts;
        } else
                early = 0;
        if (delayed && (rack->rc_always_pace == 1)) {
                rack->r_ctl.rc_agg_delayed += delayed;
                rack->r_late = 1;
        } else if (early && (rack->rc_always_pace == 1)) {
                rack->r_ctl.rc_agg_early += early;
                rack->r_early = 1;
        } else if (rack->rc_always_pace == 0) {
                /* Non-paced we are not late */
                rack->r_ctl.rc_agg_delayed = rack->r_ctl.rc_agg_early = 0;
                rack->r_early = rack->r_late = 0;
        }
        /* Now that early/late accounting is done turn off the flag */
        rack->r_ctl.rc_hpts_flags &= ~PACE_PKT_OUTPUT;
        rack->r_wanted_output = 0;
        rack->r_timer_override = 0;
        if ((tp->t_state != rack->r_state) &&
            TCPS_HAVEESTABLISHED(tp->t_state)) {
                rack_set_state(tp, rack);
        }
        segsiz = min(ctf_fixed_maxseg(tp), rack->r_ctl.rc_pace_min_segs);
        minseg = segsiz;
        if (rack->r_ctl.rc_pace_max_segs == 0)
                pace_max_seg = rack->rc_user_set_max_segs * segsiz;
        else
                pace_max_seg = rack->r_ctl.rc_pace_max_segs;
        if ((rack->r_fast_output) &&
            (doing_tlp == 0) &&
            (tp->rcv_numsacks == 0)) {
                int ret;

                error = 0;
                ret = rack_fast_output(tp, rack, ts_val, cts, ms_cts, &tv, &tot_len_this_send, &error, __LINE__);
                if (ret > 0)
                        return(ret);
                else if (error) {
                        inp = rack->rc_inp;
                        so = inp->inp_socket;
                        sb = &so->so_snd;
                        goto nomore;
                } else {
                        /* Return == 0, if there is more we can send tot_len wise fall through and send */
                        if (tot_len_this_send >= pace_max_seg)
                                return (ret);
#ifdef TCP_ACCOUNTING
                        /* We need to re-pin since fast_output un-pined */
                        sched_pin();
                        ts_val = get_cyclecount();
#endif
                        /* Fall back out so we can send any more that may bring us to pace_max_seg */
                }
        }
        inp = rack->rc_inp;
        /*
         * For TFO connections in SYN_SENT or SYN_RECEIVED,
         * only allow the initial SYN or SYN|ACK and those sent
         * by the retransmit timer.
         */
        if ((tp->t_flags & TF_FASTOPEN) &&
            ((tp->t_state == TCPS_SYN_RECEIVED) ||
             (tp->t_state == TCPS_SYN_SENT)) &&
            SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN or SYN|ACK sent */
            (tp->t_rxtshift == 0)) {              /* not a retransmit */
                rack_start_hpts_timer(rack, tp, cts, 0, 0, 0);
#ifdef TCP_ACCOUNTING
                sched_unpin();
#endif
                return (0);
        }
        /*
         * Determine length of data that should be transmitted, and flags
         * that will be used. If there is some data or critical controls
         * (SYN, RST) to send, then transmit; otherwise, investigate
         * further.
         */
        idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una);
        if (tp->t_idle_reduce) {
                if (idle && (TICKS_2_USEC(ticks - tp->t_rcvtime) >= tp->t_rxtcur))
                        rack_cc_after_idle(rack, tp);
        }
        tp->t_flags &= ~TF_LASTIDLE;
        if (idle) {
                if (tp->t_flags & TF_MORETOCOME) {
                        tp->t_flags |= TF_LASTIDLE;
                        idle = 0;
                }
        }
        if ((tp->snd_una == tp->snd_max) &&
            rack->r_ctl.rc_went_idle_time &&
            (cts > rack->r_ctl.rc_went_idle_time)) {
                tot_idle = (cts - rack->r_ctl.rc_went_idle_time);
                if (tot_idle > rack_min_probertt_hold) {
                        /* Count as a probe rtt */
                        if (rack->in_probe_rtt == 0) {
                                rack->r_ctl.rc_lower_rtt_us_cts = cts;
                                rack->r_ctl.rc_time_probertt_entered = rack->r_ctl.rc_lower_rtt_us_cts;
                                rack->r_ctl.rc_time_probertt_starts = rack->r_ctl.rc_lower_rtt_us_cts;
                                rack->r_ctl.rc_time_of_last_probertt = rack->r_ctl.rc_lower_rtt_us_cts;
                        } else {
                                rack_exit_probertt(rack, cts);
                        }
                }
        } else
                tot_idle = 0;
        if (rack_use_fsb &&
            (rack->r_ctl.fsb.tcp_ip_hdr) &&
            (rack->r_fsb_inited == 0) &&
            (rack->r_state != TCPS_CLOSED))
                rack_init_fsb_block(tp, rack, tcp_outflags[tp->t_state]);
        if (rack->rc_sendvars_notset == 1) {
                rack->rc_sendvars_notset = 0;
                /*
                 * Make sure any TCP timers (keep-alive) is not running.
                 */
                tcp_timer_stop(tp);
        }
        if ((rack->rack_no_prr == 1) &&
            (rack->rc_always_pace == 0)) {
                /*
                 * Sanity check before sending, if we have
                 * no-pacing enabled and prr is turned off that
                 * is a logistics error. Correct this by turnning
                 * prr back on. A user *must* set some form of
                 * pacing in order to turn PRR off. We do this
                 * in the output path so that we can avoid socket
                 * option ordering issues that would occur if we
                 * tried to do it while setting rack_no_prr on.
                 */
                rack->rack_no_prr = 0;
        }
        if ((rack->pcm_enabled == 1) &&
            (rack->pcm_needed == 0) &&
            (tot_idle > 0)) {
                /*
                 * We have been idle some micro seconds. We need
                 * to factor this in to see if a PCM is needed.
                 */
                uint32_t rtts_idle, rnds;

                if (tp->t_srtt)
                        rtts_idle = tot_idle / tp->t_srtt;
                else
                        rtts_idle = 0;
                rnds = rack->r_ctl.current_round - rack->r_ctl.last_pcm_round;
                rack->r_ctl.pcm_idle_rounds += rtts_idle;
                if ((rnds + rack->r_ctl.pcm_idle_rounds)  >= rack_pcm_every_n_rounds) {
                        rack->pcm_needed = 1;
                        rack_log_pcm(rack, 8, rack->r_ctl.last_pcm_round, rtts_idle, rack->r_ctl.current_round );
                }
        }
again:
        sendalot = 0;
        cts = tcp_get_usecs(&tv);
        ms_cts = tcp_tv_to_msec(&tv);
        tso = 0;
        mtu = 0;
        if (TCPS_HAVEESTABLISHED(tp->t_state) &&
            (rack->r_ctl.pcm_max_seg == 0)) {
                /*
                 * We set in our first send so we know that the ctf_fixed_maxseg
                 * has been fully set. If we do it in rack_init() we most likely
                 * see 512 bytes so we end up at 5120, not desirable.
                 */
                rack->r_ctl.pcm_max_seg = rc_init_window(rack);
                if (rack->r_ctl.pcm_max_seg < (ctf_fixed_maxseg(tp) * 10)) {
                        /*
                         * Assure our initial PCM probe is at least 10 MSS.
                         */
                        rack->r_ctl.pcm_max_seg = ctf_fixed_maxseg(tp) * 10;
                }
        }
        if ((rack->r_ctl.pcm_max_seg != 0) && (rack->pcm_needed == 1)) {
                uint32_t rw_avail, cwa;

                if (tp->snd_wnd > ctf_outstanding(tp))
                        rw_avail = tp->snd_wnd - ctf_outstanding(tp);
                else
                        rw_avail = 0;
                if (tp->snd_cwnd > ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked))
                        cwa = tp->snd_cwnd -ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                else
                        cwa = 0;
                if ((cwa >= rack->r_ctl.pcm_max_seg) &&
                    (rw_avail > rack->r_ctl.pcm_max_seg)) {
                        /* Raise up the max seg for this trip through */
                        pace_max_seg = rack->r_ctl.pcm_max_seg;
                        /* Disable any fast output */
                        rack->r_fast_output = 0;
                }
                if (rack_verbose_logging) {
                        rack_log_pcm(rack, 4,
                                     cwa, rack->r_ctl.pcm_max_seg, rw_avail);
                }
        }
        sb_offset = tp->snd_max - tp->snd_una;
        cwnd_to_use = rack->r_ctl.cwnd_to_use = tp->snd_cwnd;
        flags = tcp_outflags[tp->t_state];
        while (rack->rc_free_cnt < rack_free_cache) {
                rsm = rack_alloc(rack);
                if (rsm == NULL) {
                        if (hpts_calling)
                                /* Retry in a ms */
                                pacing_delay = (1 * HPTS_USEC_IN_MSEC);
                        so = inp->inp_socket;
                        sb = &so->so_snd;
                        goto just_return_nolock;
                }
                TAILQ_INSERT_TAIL(&rack->r_ctl.rc_free, rsm, r_tnext);
                rack->rc_free_cnt++;
                rsm = NULL;
        }
        sack_rxmit = 0;
        len = 0;
        rsm = NULL;
        if (flags & TH_RST) {
                SOCK_SENDBUF_LOCK(inp->inp_socket);
                so = inp->inp_socket;
                sb = &so->so_snd;
                goto send;
        }
        if (rack->r_ctl.rc_resend) {
                /* Retransmit timer */
                rsm = rack->r_ctl.rc_resend;
                rack->r_ctl.rc_resend = NULL;
                len = rsm->r_end - rsm->r_start;
                sack_rxmit = 1;
                sendalot = 0;
                KASSERT(SEQ_LEQ(tp->snd_una, rsm->r_start),
                        ("%s:%d: r.start:%u < SND.UNA:%u; tp:%p, rack:%p, rsm:%p",
                         __func__, __LINE__,
                         rsm->r_start, tp->snd_una, tp, rack, rsm));
                sb_offset = rsm->r_start - tp->snd_una;
                rack_validate_sizes(rack, &len, segsiz, pace_max_seg);
        } else if (rack->r_collapse_point_valid &&
                   ((rsm = rack_check_collapsed(rack, cts)) != NULL)) {
                /*
                 * If an RSM is returned then enough time has passed
                 * for us to retransmit it. Move up the collapse point,
                 * since this rsm has its chance to retransmit now.
                 */
                tcp_trace_point(rack->rc_tp, TCP_TP_COLLAPSED_RXT);
                rack->r_ctl.last_collapse_point = rsm->r_end;
                /* Are we done? */
                if (SEQ_GEQ(rack->r_ctl.last_collapse_point,
                            rack->r_ctl.high_collapse_point))
                        rack->r_collapse_point_valid = 0;
                sack_rxmit = 1;
                /* We are not doing a TLP */
                doing_tlp = 0;
                len = rsm->r_end - rsm->r_start;
                sb_offset = rsm->r_start - tp->snd_una;
                sendalot = 0;
                rack_validate_sizes(rack, &len, segsiz, pace_max_seg);
        } else if ((rsm = tcp_rack_output(tp, rack, cts)) != NULL) {
                /* We have a retransmit that takes precedence */
                if ((!IN_FASTRECOVERY(tp->t_flags)) &&
                    ((rsm->r_flags & RACK_MUST_RXT) == 0) &&
                    ((tp->t_flags & TF_WASFRECOVERY) == 0)) {
                        /* Enter recovery if not induced by a time-out */
                        rack_cong_signal(tp, CC_NDUPACK, tp->snd_una, __LINE__);
                }
#ifdef INVARIANTS
                if (SEQ_LT(rsm->r_start, tp->snd_una)) {
                        panic("Huh, tp:%p rack:%p rsm:%p start:%u < snd_una:%u\n",
                              tp, rack, rsm, rsm->r_start, tp->snd_una);
                }
#endif
                len = rsm->r_end - rsm->r_start;
                KASSERT(SEQ_LEQ(tp->snd_una, rsm->r_start),
                        ("%s:%d: r.start:%u < SND.UNA:%u; tp:%p, rack:%p, rsm:%p",
                         __func__, __LINE__,
                         rsm->r_start, tp->snd_una, tp, rack, rsm));
                sb_offset = rsm->r_start - tp->snd_una;
                sendalot = 0;
                rack_validate_sizes(rack, &len, segsiz, pace_max_seg);
                if (len > 0) {
                        sack_rxmit = 1;
                        KMOD_TCPSTAT_INC(tcps_sack_rexmits);
                        KMOD_TCPSTAT_ADD(tcps_sack_rexmit_bytes,
                                         min(len, segsiz));
                }
        } else if (rack->r_ctl.rc_tlpsend) {
                /* Tail loss probe */
                long cwin;
                long tlen;

                /*
                 * Check if we can do a TLP with a RACK'd packet
                 * this can happen if we are not doing the rack
                 * cheat and we skipped to a TLP and it
                 * went off.
                 */
                rsm = rack->r_ctl.rc_tlpsend;
                /* We are doing a TLP make sure the flag is preent */
                rsm->r_flags |= RACK_TLP;
                rack->r_ctl.rc_tlpsend = NULL;
                sack_rxmit = 1;
                tlen = rsm->r_end - rsm->r_start;
                if (tlen > segsiz)
                        tlen = segsiz;
                KASSERT(SEQ_LEQ(tp->snd_una, rsm->r_start),
                        ("%s:%d: r.start:%u < SND.UNA:%u; tp:%p, rack:%p, rsm:%p",
                         __func__, __LINE__,
                         rsm->r_start, tp->snd_una, tp, rack, rsm));
                sb_offset = rsm->r_start - tp->snd_una;
                cwin = min(tp->snd_wnd, tlen);
                len = cwin;
        }
        if (rack->r_must_retran &&
            (doing_tlp == 0) &&
            (SEQ_GT(tp->snd_max, tp->snd_una)) &&
            (rsm == NULL)) {
                /*
                 * There are two different ways that we
                 * can get into this block:
                 * a) This is a non-sack connection, we had a time-out
                 *    and thus r_must_retran was set and everything
                 *    left outstanding as been marked for retransmit.
                 * b) The MTU of the path shrank, so that everything
                 *    was marked to be retransmitted with the smaller
                 *    mtu and r_must_retran was set.
                 *
                 * This means that we expect the sendmap (outstanding)
                 * to all be marked must. We can use the tmap to
                 * look at them.
                 *
                 */
                int sendwin, flight;

                sendwin = min(tp->snd_wnd, tp->snd_cwnd);
                flight = ctf_flight_size(tp, rack->r_ctl.rc_out_at_rto);
                if (flight >= sendwin) {
                        /*
                         * We can't send yet.
                         */
                        so = inp->inp_socket;
                        sb = &so->so_snd;
                        goto just_return_nolock;
                }
                /*
                 * This is the case a/b mentioned above. All
                 * outstanding/not-acked should be marked.
                 * We can use the tmap to find them.
                 */
                rsm = TAILQ_FIRST(&rack->r_ctl.rc_tmap);
                if (rsm == NULL) {
                        /* TSNH */
                        rack->r_must_retran = 0;
                        rack->r_ctl.rc_out_at_rto = 0;
                        so = inp->inp_socket;
                        sb = &so->so_snd;
                        goto just_return_nolock;
                }
                if ((rsm->r_flags & RACK_MUST_RXT) == 0) {
                        /*
                         * The first one does not have the flag, did we collapse
                         * further up in our list?
                         */
                        rack->r_must_retran = 0;
                        rack->r_ctl.rc_out_at_rto = 0;
                        rsm = NULL;
                        sack_rxmit = 0;
                } else {
                        sack_rxmit = 1;
                        len = rsm->r_end - rsm->r_start;
                        sb_offset = rsm->r_start - tp->snd_una;
                        sendalot = 0;
                        if ((rack->full_size_rxt == 0) &&
                            (rack->shape_rxt_to_pacing_min == 0) &&
                            (len >= segsiz))
                                len = segsiz;
                        else if (rack->shape_rxt_to_pacing_min &&
                                 rack->gp_ready) {
                                /* We use pacing min as shaping len req */
                                uint32_t maxlen;

                                maxlen = rack_get_hpts_pacing_min_for_bw(rack, segsiz);
                                if (len > maxlen)
                                        len = maxlen;
                        }
                        /*
                         * Delay removing the flag RACK_MUST_RXT so
                         * that the fastpath for retransmit will
                         * work with this rsm.
                         */
                }
        }
        /*
         * Enforce a connection sendmap count limit if set
         * as long as we are not retransmiting.
         */
        if ((rsm == NULL) &&
            (V_tcp_map_entries_limit > 0) &&
            (rack->r_ctl.rc_num_maps_alloced >= V_tcp_map_entries_limit)) {
                counter_u64_add(rack_to_alloc_limited, 1);
                if (!rack->alloc_limit_reported) {
                        rack->alloc_limit_reported = 1;
                        counter_u64_add(rack_alloc_limited_conns, 1);
                }
                so = inp->inp_socket;
                sb = &so->so_snd;
                goto just_return_nolock;
        }
        if (rsm && (rsm->r_flags & RACK_HAS_FIN)) {
                /* we are retransmitting the fin */
                len--;
                if (len) {
                        /*
                         * When retransmitting data do *not* include the
                         * FIN. This could happen from a TLP probe.
                         */
                        flags &= ~TH_FIN;
                }
        }
        if (rsm && rack->r_fsb_inited &&
            rack_use_rsm_rfo &&
            ((rsm->r_flags & RACK_HAS_FIN) == 0)) {
                int ret;

                ret = rack_fast_rsm_output(tp, rack, rsm, ts_val, cts, ms_cts, &tv, len, doing_tlp);
                if (ret == 0)
                        return (0);
        }
        so = inp->inp_socket;
        sb = &so->so_snd;
        if (do_a_prefetch == 0) {
                kern_prefetch(sb, &do_a_prefetch);
                do_a_prefetch = 1;
        }
#ifdef NETFLIX_SHARED_CWND
        if ((tp->t_flags2 & TF2_TCP_SCWND_ALLOWED) &&
            rack->rack_enable_scwnd) {
                /* We are doing cwnd sharing */
                if (rack->gp_ready &&
                    (rack->rack_attempted_scwnd == 0) &&
                    (rack->r_ctl.rc_scw == NULL) &&
                    tp->t_lib) {
                        /* The pcbid is in, lets make an attempt */
                        counter_u64_add(rack_try_scwnd, 1);
                        rack->rack_attempted_scwnd = 1;
                        rack->r_ctl.rc_scw = tcp_shared_cwnd_alloc(tp,
                                                                   &rack->r_ctl.rc_scw_index,
                                                                   segsiz);
                }
                if (rack->r_ctl.rc_scw &&
                    (rack->rack_scwnd_is_idle == 1) &&
                    sbavail(&so->so_snd)) {
                        /* we are no longer out of data */
                        tcp_shared_cwnd_active(rack->r_ctl.rc_scw, rack->r_ctl.rc_scw_index);
                        rack->rack_scwnd_is_idle = 0;
                }
                if (rack->r_ctl.rc_scw) {
                        /* First lets update and get the cwnd */
                        rack->r_ctl.cwnd_to_use = cwnd_to_use = tcp_shared_cwnd_update(rack->r_ctl.rc_scw,
                                                                                       rack->r_ctl.rc_scw_index,
                                                                                       tp->snd_cwnd, tp->snd_wnd, segsiz);
                }
        }
#endif
        /*
         * Get standard flags, and add SYN or FIN if requested by 'hidden'
         * state flags.
         */
        if (tp->t_flags & TF_NEEDFIN)
                flags |= TH_FIN;
        if (tp->t_flags & TF_NEEDSYN)
                flags |= TH_SYN;
        if ((sack_rxmit == 0) && (prefetch_rsm == 0)) {
                void *end_rsm;
                end_rsm = TAILQ_LAST_FAST(&rack->r_ctl.rc_tmap, rack_sendmap, r_tnext);
                if (end_rsm)
                        kern_prefetch(end_rsm, &prefetch_rsm);
                prefetch_rsm = 1;
        }
        SOCK_SENDBUF_LOCK(so);
        if ((sack_rxmit == 0) &&
            (TCPS_HAVEESTABLISHED(tp->t_state) ||
            (tp->t_flags & TF_FASTOPEN))) {
                /*
                 * We are not retransmitting (sack_rxmit is 0) so we
                 * are sending new data. This is always based on snd_max.
                 * Now in theory snd_max may be equal to snd_una, if so
                 * then nothing is outstanding and the offset would be 0.
                 */
                uint32_t avail;

                avail = sbavail(sb);
                if (SEQ_GT(tp->snd_max, tp->snd_una) && avail)
                        sb_offset = tp->snd_max - tp->snd_una;
                else
                        sb_offset = 0;
                if ((IN_FASTRECOVERY(tp->t_flags) == 0) || rack->rack_no_prr) {
                        if (rack->r_ctl.rc_tlp_new_data) {
                                /* TLP is forcing out new data */
                                if (rack->r_ctl.rc_tlp_new_data > (uint32_t) (avail - sb_offset)) {
                                        rack->r_ctl.rc_tlp_new_data = (uint32_t) (avail - sb_offset);
                                }
                                if ((rack->r_ctl.rc_tlp_new_data + sb_offset) > tp->snd_wnd) {
                                        if (tp->snd_wnd > sb_offset)
                                                len = tp->snd_wnd - sb_offset;
                                        else
                                                len = 0;
                                } else {
                                        len = rack->r_ctl.rc_tlp_new_data;
                                }
                                rack->r_ctl.rc_tlp_new_data = 0;
                        }  else {
                                len = rack_what_can_we_send(tp, rack, cwnd_to_use, avail, sb_offset);
                        }
                        if ((rack->r_ctl.crte == NULL) &&
                            IN_FASTRECOVERY(tp->t_flags) &&
                            (rack->full_size_rxt == 0) &&
                            (rack->shape_rxt_to_pacing_min == 0) &&
                            (len > segsiz)) {
                                /*
                                 * For prr=off, we need to send only 1 MSS
                                 * at a time. We do this because another sack could
                                 * be arriving that causes us to send retransmits and
                                 * we don't want to be on a long pace due to a larger send
                                 * that keeps us from sending out the retransmit.
                                 */
                                len = segsiz;
                        } else if (rack->shape_rxt_to_pacing_min &&
                                   rack->gp_ready) {
                                /* We use pacing min as shaping len req */
                                uint32_t maxlen;

                                maxlen = rack_get_hpts_pacing_min_for_bw(rack, segsiz);
                                if (len > maxlen)
                                        len = maxlen;
                        }/* The else is full_size_rxt is on so send it all */
                } else {
                        uint32_t outstanding;
                        /*
                         * We are inside of a Fast recovery episode, this
                         * is caused by a SACK or 3 dup acks. At this point
                         * we have sent all the retransmissions and we rely
                         * on PRR to dictate what we will send in the form of
                         * new data.
                         */

                        outstanding = tp->snd_max - tp->snd_una;
                        if ((rack->r_ctl.rc_prr_sndcnt + outstanding) > tp->snd_wnd) {
                                if (tp->snd_wnd > outstanding) {
                                        len = tp->snd_wnd - outstanding;
                                        /* Check to see if we have the data */
                                        if ((sb_offset + len) > avail) {
                                                /* It does not all fit */
                                                if (avail > sb_offset)
                                                        len = avail - sb_offset;
                                                else
                                                        len = 0;
                                        }
                                } else {
                                        len = 0;
                                }
                        } else if (avail > sb_offset) {
                                len = avail - sb_offset;
                        } else {
                                len = 0;
                        }
                        if (len > 0) {
                                if (len > rack->r_ctl.rc_prr_sndcnt) {
                                        len = rack->r_ctl.rc_prr_sndcnt;
                                }
                                if (len > 0) {
                                        sub_from_prr = 1;
                                }
                        }
                        if (len > segsiz) {
                                /*
                                 * We should never send more than a MSS when
                                 * retransmitting or sending new data in prr
                                 * mode unless the override flag is on. Most
                                 * likely the PRR algorithm is not going to
                                 * let us send a lot as well :-)
                                 */
                                if (rack->r_ctl.rc_prr_sendalot == 0) {
                                        len = segsiz;
                                }
                        } else if (len < segsiz) {
                                /*
                                 * Do we send any? The idea here is if the
                                 * send empty's the socket buffer we want to
                                 * do it. However if not then lets just wait
                                 * for our prr_sndcnt to get bigger.
                                 */
                                long leftinsb;

                                leftinsb = sbavail(sb) - sb_offset;
                                if (leftinsb > len) {
                                        /* This send does not empty the sb */
                                        len = 0;
                                }
                        }
                }
        } else if (!TCPS_HAVEESTABLISHED(tp->t_state)) {
                /*
                 * If you have not established
                 * and are not doing FAST OPEN
                 * no data please.
                 */
                if ((sack_rxmit == 0) &&
                    !(tp->t_flags & TF_FASTOPEN)) {
                        len = 0;
                        sb_offset = 0;
                }
        }
        if (prefetch_so_done == 0) {
                kern_prefetch(so, &prefetch_so_done);
                prefetch_so_done = 1;
        }
        orig_len = len;
        /*
         * Lop off SYN bit if it has already been sent.  However, if this is
         * SYN-SENT state and if segment contains data and if we don't know
         * that foreign host supports TAO, suppress sending segment.
         */
        if ((flags & TH_SYN) &&
            SEQ_GT(tp->snd_max, tp->snd_una) &&
            ((sack_rxmit == 0) &&
             (tp->t_rxtshift == 0))) {
                /*
                 * When sending additional segments following a TFO SYN|ACK,
                 * do not include the SYN bit.
                 */
                if ((tp->t_flags & TF_FASTOPEN) &&
                    (tp->t_state == TCPS_SYN_RECEIVED))
                        flags &= ~TH_SYN;
        }
        /*
         * Be careful not to send data and/or FIN on SYN segments. This
         * measure is needed to prevent interoperability problems with not
         * fully conformant TCP implementations.
         */
        if ((flags & TH_SYN) && (tp->t_flags & TF_NOOPT)) {
                len = 0;
                flags &= ~TH_FIN;
        }
        /*
         * On TFO sockets, ensure no data is sent in the following cases:
         *
         *  - When retransmitting SYN|ACK on a passively-created socket
         *
         *  - When retransmitting SYN on an actively created socket
         *
         *  - When sending a zero-length cookie (cookie request) on an
         *    actively created socket
         *
         *  - When the socket is in the CLOSED state (RST is being sent)
         */
        if ((tp->t_flags & TF_FASTOPEN) &&
            (((flags & TH_SYN) && (tp->t_rxtshift > 0)) ||
             ((tp->t_state == TCPS_SYN_SENT) &&
              (tp->t_tfo_client_cookie_len == 0)) ||
             (flags & TH_RST))) {
                sack_rxmit = 0;
                len = 0;
        }
        /* Without fast-open there should never be data sent on a SYN */
        if ((flags & TH_SYN) && !(tp->t_flags & TF_FASTOPEN)) {
                len = 0;
        }
        if ((len > segsiz) && (tcp_dsack_block_exists(tp))) {
                /* We only send 1 MSS if we have a DSACK block */
                add_flag |= RACK_SENT_W_DSACK;
                len = segsiz;
        }
        if (len <= 0) {
                /*
                 * We have nothing to send, or the window shrank, or
                 * is closed, do we need to go into persists?
                 */
                len = 0;
                if ((tp->snd_wnd == 0) &&
                    (TCPS_HAVEESTABLISHED(tp->t_state)) &&
                    (tp->snd_una == tp->snd_max) &&
                    (sb_offset < (int)sbavail(sb))) {
                        rack_enter_persist(tp, rack, cts, tp->snd_una);
                }
        } else if ((rsm == NULL) &&
                   (doing_tlp == 0) &&
                   (len < pace_max_seg)) {
                /*
                 * We are not sending a maximum sized segment for
                 * some reason. Should we not send anything (think
                 * sws or persists)?
                 */
                if ((tp->snd_wnd < min((rack->r_ctl.rc_high_rwnd/2), minseg)) &&
                    (TCPS_HAVEESTABLISHED(tp->t_state)) &&
                    (len < minseg) &&
                    (len < (int)(sbavail(sb) - sb_offset))) {
                        /*
                         * Here the rwnd is less than
                         * the minimum pacing size, this is not a retransmit,
                         * we are established and
                         * the send is not the last in the socket buffer
                         * we send nothing, and we may enter persists
                         * if nothing is outstanding.
                         */
                        len = 0;
                        if (tp->snd_max == tp->snd_una) {
                                /*
                                 * Nothing out we can
                                 * go into persists.
                                 */
                                rack_enter_persist(tp, rack, cts, tp->snd_una);
                        }
                } else if ((cwnd_to_use >= max(minseg, (segsiz * 4))) &&
                           (ctf_flight_size(tp, rack->r_ctl.rc_sacked) > (2 * segsiz)) &&
                           (len < (int)(sbavail(sb) - sb_offset)) &&
                           (len < minseg)) {
                        /*
                         * Here we are not retransmitting, and
                         * the cwnd is not so small that we could
                         * not send at least a min size (rxt timer
                         * not having gone off), We have 2 segments or
                         * more already in flight, its not the tail end
                         * of the socket buffer  and the cwnd is blocking
                         * us from sending out a minimum pacing segment size.
                         * Lets not send anything.
                         */
                        len = 0;
                } else if (((tp->snd_wnd - ctf_outstanding(tp)) <
                            min((rack->r_ctl.rc_high_rwnd/2), minseg)) &&
                           (ctf_flight_size(tp, rack->r_ctl.rc_sacked) > (2 * segsiz)) &&
                           (len < (int)(sbavail(sb) - sb_offset)) &&
                           (TCPS_HAVEESTABLISHED(tp->t_state))) {
                        /*
                         * Here we have a send window but we have
                         * filled it up and we can't send another pacing segment.
                         * We also have in flight more than 2 segments
                         * and we are not completing the sb i.e. we allow
                         * the last bytes of the sb to go out even if
                         * its not a full pacing segment.
                         */
                        len = 0;
                } else if ((rack->r_ctl.crte != NULL) &&
                           (tp->snd_wnd >= (pace_max_seg * max(1, rack_hw_rwnd_factor))) &&
                           (cwnd_to_use >= (pace_max_seg + (4 * segsiz))) &&
                           (ctf_flight_size(tp, rack->r_ctl.rc_sacked) >= (2 * segsiz)) &&
                           (len < (int)(sbavail(sb) - sb_offset))) {
                        /*
                         * Here we are doing hardware pacing, this is not a TLP,
                         * we are not sending a pace max segment size, there is rwnd
                         * room to send at least N pace_max_seg, the cwnd is greater
                         * than or equal to a full pacing segments plus 4 mss and we have 2 or
                         * more segments in flight and its not the tail of the socket buffer.
                         *
                         * We don't want to send instead we need to get more ack's in to
                         * allow us to send a full pacing segment. Normally, if we are pacing
                         * about the right speed, we should have finished our pacing
                         * send as most of the acks have come back if we are at the
                         * right rate. This is a bit fuzzy since return path delay
                         * can delay the acks, which is why we want to make sure we
                         * have cwnd space to have a bit more than a max pace segments in flight.
                         *
                         * If we have not gotten our acks back we are pacing at too high a
                         * rate delaying will not hurt and will bring our GP estimate down by
                         * injecting the delay. If we don't do this we will send
                         * 2 MSS out in response to the acks being clocked in which
                         * defeats the point of hw-pacing (i.e. to help us get
                         * larger TSO's out).
                         */
                        len = 0;
                }

        }
        /* len will be >= 0 after this point. */
        KASSERT(len >= 0, ("[%s:%d]: len < 0", __func__, __LINE__));
        rack_sndbuf_autoscale(rack);
        /*
         * Decide if we can use TCP Segmentation Offloading (if supported by
         * hardware).
         *
         * TSO may only be used if we are in a pure bulk sending state.  The
         * presence of TCP-MD5, SACK retransmits, SACK advertizements and IP
         * options prevent using TSO.  With TSO the TCP header is the same
         * (except for the sequence number) for all generated packets.  This
         * makes it impossible to transmit any options which vary per
         * generated segment or packet.
         *
         * IPv4 handling has a clear separation of ip options and ip header
         * flags while IPv6 combines both in in6p_outputopts. ip6_optlen() does
         * the right thing below to provide length of just ip options and thus
         * checking for ipoptlen is enough to decide if ip options are present.
         */
        ipoptlen = 0;
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
        /*
         * Pre-calculate here as we save another lookup into the darknesses
         * of IPsec that way and can actually decide if TSO is ok.
         */
#ifdef INET6
        if (isipv6 && IPSEC_ENABLED(ipv6))
                ipsec_optlen = IPSEC_HDRSIZE(ipv6, inp);
#ifdef INET
        else
#endif
#endif                          /* INET6 */
#ifdef INET
                if (IPSEC_ENABLED(ipv4))
                        ipsec_optlen = IPSEC_HDRSIZE(ipv4, inp);
#endif                          /* INET */
#endif

#if defined(IPSEC) || defined(IPSEC_SUPPORT)
        ipoptlen += ipsec_optlen;
#endif
        if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > segsiz &&
            (tp->t_port == 0) &&
            ((tp->t_flags & TF_SIGNATURE) == 0) &&
            sack_rxmit == 0 &&
            ipoptlen == 0)
                tso = 1;
        {
                uint32_t outstanding __unused;

                outstanding = tp->snd_max - tp->snd_una;
                if (tp->t_flags & TF_SENTFIN) {
                        /*
                         * If we sent a fin, snd_max is 1 higher than
                         * snd_una
                         */
                        outstanding--;
                }
                if (sack_rxmit) {
                        if ((rsm->r_flags & RACK_HAS_FIN) == 0)
                                flags &= ~TH_FIN;
                }
        }
        recwin = lmin(lmax(sbspace(&so->so_rcv), 0),
                      (long)TCP_MAXWIN << tp->rcv_scale);

        /*
         * Sender silly window avoidance.   We transmit under the following
         * conditions when len is non-zero:
         *
         * - We have a full segment (or more with TSO) - This is the last
         * buffer in a write()/send() and we are either idle or running
         * NODELAY - we've timed out (e.g. persist timer) - we have more
         * then 1/2 the maximum send window's worth of data (receiver may be
         * limited the window size) - we need to retransmit
         */
        if (len) {
                if (len >= segsiz) {
                        goto send;
                }
                /*
                 * NOTE! on localhost connections an 'ack' from the remote
                 * end may occur synchronously with the output and cause us
                 * to flush a buffer queued with moretocome.  XXX
                 *
                 */
                if (!(tp->t_flags & TF_MORETOCOME) &&   /* normal case */
                    (idle || (tp->t_flags & TF_NODELAY)) &&
                    ((uint32_t)len + (uint32_t)sb_offset >= sbavail(sb)) &&
                    (tp->t_flags & TF_NOPUSH) == 0) {
                        pass = 2;
                        goto send;
                }
                if ((tp->snd_una == tp->snd_max) && len) {      /* Nothing outstanding */
                        pass = 22;
                        goto send;
                }
                if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) {
                        pass = 4;
                        goto send;
                }
                if (sack_rxmit) {
                        pass = 6;
                        goto send;
                }
                if (((tp->snd_wnd - ctf_outstanding(tp)) < segsiz) &&
                    (ctf_outstanding(tp) < (segsiz * 2))) {
                        /*
                         * We have less than two MSS outstanding (delayed ack)
                         * and our rwnd will not let us send a full sized
                         * MSS. Lets go ahead and let this small segment
                         * out because we want to try to have at least two
                         * packets inflight to not be caught by delayed ack.
                         */
                        pass = 12;
                        goto send;
                }
        }
        /*
         * Sending of standalone window updates.
         *
         * Window updates are important when we close our window due to a
         * full socket buffer and are opening it again after the application
         * reads data from it.  Once the window has opened again and the
         * remote end starts to send again the ACK clock takes over and
         * provides the most current window information.
         *
         * We must avoid the silly window syndrome whereas every read from
         * the receive buffer, no matter how small, causes a window update
         * to be sent.  We also should avoid sending a flurry of window
         * updates when the socket buffer had queued a lot of data and the
         * application is doing small reads.
         *
         * Prevent a flurry of pointless window updates by only sending an
         * update when we can increase the advertized window by more than
         * 1/4th of the socket buffer capacity.  When the buffer is getting
         * full or is very small be more aggressive and send an update
         * whenever we can increase by two mss sized segments. In all other
         * situations the ACK's to new incoming data will carry further
         * window increases.
         *
         * Don't send an independent window update if a delayed ACK is
         * pending (it will get piggy-backed on it) or the remote side
         * already has done a half-close and won't send more data.  Skip
         * this if the connection is in T/TCP half-open state.
         */
        if (recwin > 0 && !(tp->t_flags & TF_NEEDSYN) &&
            !(tp->t_flags & TF_DELACK) &&
            !TCPS_HAVERCVDFIN(tp->t_state)) {
                /*
                 * "adv" is the amount we could increase the window, taking
                 * into account that we are limited by TCP_MAXWIN <<
                 * tp->rcv_scale.
                 */
                int32_t adv;
                int oldwin;

                adv = recwin;
                if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) {
                        oldwin = (tp->rcv_adv - tp->rcv_nxt);
                        if (adv > oldwin)
                                adv -= oldwin;
                        else {
                                /* We can't increase the window */
                                adv = 0;
                        }
                } else
                        oldwin = 0;

                /*
                 * If the new window size ends up being the same as or less
                 * than the old size when it is scaled, then don't force
                 * a window update.
                 */
                if (oldwin >> tp->rcv_scale >= (adv + oldwin) >> tp->rcv_scale)
                        goto dontupdate;

                if (adv >= (int32_t)(2 * segsiz) &&
                    (adv >= (int32_t)(so->so_rcv.sb_hiwat / 4) ||
                     recwin <= (int32_t)(so->so_rcv.sb_hiwat / 8) ||
                     so->so_rcv.sb_hiwat <= 8 * segsiz)) {
                        pass = 7;
                        goto send;
                }
                if (2 * adv >= (int32_t) so->so_rcv.sb_hiwat) {
                        pass = 23;
                        goto send;
                }
        }
dontupdate:

        /*
         * Send if we owe the peer an ACK, RST, SYN, or urgent data.  ACKNOW
         * is also a catch-all for the retransmit timer timeout case.
         */
        if (tp->t_flags & TF_ACKNOW) {
                pass = 8;
                goto send;
        }
        if (((flags & TH_SYN) && (tp->t_flags & TF_NEEDSYN) == 0)) {
                pass = 9;
                goto send;
        }
        /*
         * If our state indicates that FIN should be sent and we have not
         * yet done so, then we need to send.
         */
        if ((flags & TH_FIN) &&
            (tp->snd_max == tp->snd_una)) {
                pass = 11;
                goto send;
        }
        /*
         * No reason to send a segment, just return.
         */
just_return:
        SOCK_SENDBUF_UNLOCK(so);
just_return_nolock:
        {
                int app_limited = CTF_JR_SENT_DATA;

                if ((tp->t_flags & TF_FASTOPEN) == 0 &&
                    (flags & TH_FIN) &&
                    (len == 0) &&
                    (sbused(sb) == (tp->snd_max - tp->snd_una)) &&
                    ((tp->snd_max - tp->snd_una) <= segsiz)) {
                        /*
                         * Ok less than or right at a MSS is
                         * outstanding. The original FreeBSD stack would
                         * have sent a FIN, which can speed things up for
                         * a transactional application doing a MSG_WAITALL.
                         * To speed things up since we do *not* send a FIN
                         * if data is outstanding, we send a "challenge ack".
                         * The idea behind that is instead of having to have
                         * the peer wait for the delayed-ack timer to run off
                         * we send an ack that makes the peer send us an ack.
                         *
                         * Note we do not send anything if its been less than
                         * a srtt.
                         */
                        uint64_t tmark;

                        tmark = tcp_get_u64_usecs(&tv);
                        if ((tmark > rack->r_ctl.lt_timemark) &&
                            (((tmark - rack->r_ctl.lt_timemark) / 1000) > tp->t_srtt)) {
                                rack_send_ack_challange(rack);
                        }
                }
                if (tot_len_this_send > 0) {
                        rack->r_ctl.fsb.recwin = recwin;
                        pacing_delay = rack_get_pacing_delay(rack, tp, tot_len_this_send, NULL, segsiz, __LINE__);
                        if ((error == 0) &&
                            rack_use_rfo &&
                            ((flags & (TH_SYN|TH_FIN)) == 0) &&
                            (ipoptlen == 0) &&
                            rack->r_fsb_inited &&
                            TCPS_HAVEESTABLISHED(tp->t_state) &&
                            ((IN_RECOVERY(tp->t_flags)) == 0) &&
                            (doing_tlp == 0) &&
                            (rack->r_must_retran == 0) &&
                            ((tp->t_flags & TF_NEEDFIN) == 0) &&
                            (len > 0) && (orig_len > 0) &&
                            (orig_len > len) &&
                            ((orig_len - len) >= segsiz) &&
                            ((optlen == 0) ||
                             ((optlen == TCPOLEN_TSTAMP_APPA) && (to.to_flags & TOF_TS)))) {
                                /* We can send at least one more MSS using our fsb */
                                rack_setup_fast_output(tp, rack, sb, len, orig_len,
                                                       segsiz, pace_max_seg, hw_tls, flags);
                        } else
                                rack->r_fast_output = 0;
                        rack_log_fsb(rack, tp, so, flags,
                                     ipoptlen, orig_len, len, 0,
                                     1, optlen, __LINE__, 1);
                        /* Assure when we leave that snd_nxt will point to top */
                        if (SEQ_GT(tp->snd_max, tp->snd_nxt))
                                tp->snd_nxt = tp->snd_max;
                } else {
                        int end_window = 0;
                        uint32_t seq = tp->gput_ack;

                        rsm = tqhash_max(rack->r_ctl.tqh);
                        if (rsm) {
                                /*
                                 * Mark the last sent that we just-returned (hinting
                                 * that delayed ack may play a role in any rtt measurement).
                                 */
                                rsm->r_just_ret = 1;
                        }
                        counter_u64_add(rack_out_size[TCP_MSS_ACCT_JUSTRET], 1);
                        rack->r_ctl.rc_agg_delayed = 0;
                        rack->r_early = 0;
                        rack->r_late = 0;
                        rack->r_ctl.rc_agg_early = 0;
                        if ((ctf_outstanding(tp) +
                             min(max(segsiz, (rack->r_ctl.rc_high_rwnd/2)),
                                 minseg)) >= tp->snd_wnd) {
                                /* We are limited by the rwnd */
                                app_limited = CTF_JR_RWND_LIMITED;
                                if (IN_FASTRECOVERY(tp->t_flags))
                                        rack->r_ctl.rc_prr_sndcnt = 0;
                        } else if (ctf_outstanding(tp) >= sbavail(sb)) {
                                /* We are limited by whats available -- app limited */
                                app_limited = CTF_JR_APP_LIMITED;
                                if (IN_FASTRECOVERY(tp->t_flags))
                                        rack->r_ctl.rc_prr_sndcnt = 0;
                        } else if ((idle == 0) &&
                                   ((tp->t_flags & TF_NODELAY) == 0) &&
                                   ((uint32_t)len + (uint32_t)sb_offset >= sbavail(sb)) &&
                                   (len < segsiz)) {
                                /*
                                 * No delay is not on and the
                                 * user is sending less than 1MSS. This
                                 * brings out SWS avoidance so we
                                 * don't send. Another app-limited case.
                                 */
                                app_limited = CTF_JR_APP_LIMITED;
                        } else if (tp->t_flags & TF_NOPUSH) {
                                /*
                                 * The user has requested no push of
                                 * the last segment and we are
                                 * at the last segment. Another app
                                 * limited case.
                                 */
                                app_limited = CTF_JR_APP_LIMITED;
                        } else if ((ctf_outstanding(tp) + minseg) > cwnd_to_use) {
                                /* Its the cwnd */
                                app_limited = CTF_JR_CWND_LIMITED;
                        } else if (IN_FASTRECOVERY(tp->t_flags) &&
                                   (rack->rack_no_prr == 0) &&
                                   (rack->r_ctl.rc_prr_sndcnt < segsiz)) {
                                app_limited = CTF_JR_PRR;
                        } else {
                                /* Now why here are we not sending? */
#ifdef NOW
#ifdef INVARIANTS
                                panic("rack:%p hit JR_ASSESSING case cwnd_to_use:%u?", rack, cwnd_to_use);
#endif
#endif
                                app_limited = CTF_JR_ASSESSING;
                        }
                        /*
                         * App limited in some fashion, for our pacing GP
                         * measurements we don't want any gap (even cwnd).
                         * Close  down the measurement window.
                         */
                        if (rack_cwnd_block_ends_measure &&
                            ((app_limited == CTF_JR_CWND_LIMITED) ||
                             (app_limited == CTF_JR_PRR))) {
                                /*
                                 * The reason we are not sending is
                                 * the cwnd (or prr). We have been configured
                                 * to end the measurement window in
                                 * this case.
                                 */
                                end_window = 1;
                        } else if (rack_rwnd_block_ends_measure &&
                                   (app_limited == CTF_JR_RWND_LIMITED)) {
                                /*
                                 * We are rwnd limited and have been
                                 * configured to end the measurement
                                 * window in this case.
                                 */
                                end_window = 1;
                        } else if (app_limited == CTF_JR_APP_LIMITED) {
                                /*
                                 * A true application limited period, we have
                                 * ran out of data.
                                 */
                                end_window = 1;
                        } else if (app_limited == CTF_JR_ASSESSING) {
                                /*
                                 * In the assessing case we hit the end of
                                 * the if/else and had no known reason
                                 * This will panic us under invariants..
                                 *
                                 * If we get this out in logs we need to
                                 * investagate which reason we missed.
                                 */
                                end_window = 1;
                        }
                        if (end_window) {
                                uint8_t log = 0;

                                /* Adjust the Gput measurement */
                                if ((tp->t_flags & TF_GPUTINPROG) &&
                                    SEQ_GT(tp->gput_ack, tp->snd_max)) {
                                        tp->gput_ack = tp->snd_max;
                                        if ((tp->gput_ack - tp->gput_seq) < (MIN_GP_WIN * segsiz)) {
                                                /*
                                                 * There is not enough to measure.
                                                 */
                                                tp->t_flags &= ~TF_GPUTINPROG;
                                                rack_log_pacing_delay_calc(rack, (tp->gput_ack - tp->gput_seq) /*flex2*/,
                                                                           rack->r_ctl.rc_gp_srtt /*flex1*/,
                                                                           tp->gput_seq,
                                                                           0, 0, 18, __LINE__, NULL, 0);
                                        } else
                                                log = 1;
                                }
                                /* Mark the last packet as app limited */
                                rsm = tqhash_max(rack->r_ctl.tqh);
                                if (rsm && ((rsm->r_flags & RACK_APP_LIMITED) == 0)) {
                                        if (rack->r_ctl.rc_app_limited_cnt == 0)
                                                rack->r_ctl.rc_end_appl = rack->r_ctl.rc_first_appl = rsm;
                                        else {
                                                /*
                                                 * Go out to the end app limited and mark
                                                 * this new one as next and move the end_appl up
                                                 * to this guy.
                                                 */
                                                if (rack->r_ctl.rc_end_appl)
                                                        rack->r_ctl.rc_end_appl->r_nseq_appl = rsm->r_start;
                                                rack->r_ctl.rc_end_appl = rsm;
                                        }
                                        rsm->r_flags |= RACK_APP_LIMITED;
                                        rack->r_ctl.rc_app_limited_cnt++;
                                }
                                if (log)
                                        rack_log_pacing_delay_calc(rack,
                                                                   rack->r_ctl.rc_app_limited_cnt, seq,
                                                                   tp->gput_ack, 0, 0, 4, __LINE__, NULL, 0);
                        }
                }
                /* Check if we need to go into persists or not */
                if ((tp->snd_max == tp->snd_una) &&
                    TCPS_HAVEESTABLISHED(tp->t_state) &&
                    sbavail(sb) &&
                    (sbavail(sb) > tp->snd_wnd) &&
                    (tp->snd_wnd < min((rack->r_ctl.rc_high_rwnd/2), minseg))) {
                        /* Yes lets make sure to move to persist before timer-start */
                        rack_enter_persist(tp, rack, rack->r_ctl.rc_rcvtime, tp->snd_una);
                }
                rack_start_hpts_timer(rack, tp, cts, pacing_delay, tot_len_this_send, sup_rack);
                rack_log_type_just_return(rack, cts, tot_len_this_send, pacing_delay, hpts_calling, app_limited, cwnd_to_use);
        }
#ifdef NETFLIX_SHARED_CWND
        if ((sbavail(sb) == 0) &&
            rack->r_ctl.rc_scw) {
                tcp_shared_cwnd_idle(rack->r_ctl.rc_scw, rack->r_ctl.rc_scw_index);
                rack->rack_scwnd_is_idle = 1;
        }
#endif
#ifdef TCP_ACCOUNTING
        if (tot_len_this_send > 0) {
                crtsc = get_cyclecount();
                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                        tp->tcp_cnt_counters[SND_OUT_DATA]++;
                        tp->tcp_proc_time[SND_OUT_DATA] += (crtsc - ts_val);
                        tp->tcp_cnt_counters[CNT_OF_MSS_OUT] += ((tot_len_this_send + segsiz - 1) / segsiz);
                }
        } else {
                crtsc = get_cyclecount();
                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                        tp->tcp_cnt_counters[SND_LIMITED]++;
                        tp->tcp_proc_time[SND_LIMITED] += (crtsc - ts_val);
                }
        }
        sched_unpin();
#endif
        return (0);

send:
        if ((rack->r_ctl.crte != NULL) &&
            (rsm == NULL) &&
            ((rack->rc_hw_nobuf == 1) ||
             (rack_hw_check_queue && (check_done == 0)))) {
                /*
                 * We only want to do this once with the hw_check_queue,
                 * for the enobuf case we would only do it once if
                 * we come around to again, the flag will be clear.
                 */
                check_done = 1;
                pacing_delay = rack_check_queue_level(rack, tp, &tv, cts, len, segsiz);
                if (pacing_delay) {
                        rack->r_ctl.rc_agg_delayed = 0;
                        rack->r_ctl.rc_agg_early = 0;
                        rack->r_early = 0;
                        rack->r_late = 0;
                        SOCK_SENDBUF_UNLOCK(so);
                        goto skip_all_send;
                }
        }
        if (rsm || sack_rxmit)
                counter_u64_add(rack_nfto_resend, 1);
        else
                counter_u64_add(rack_non_fto_send, 1);
        if ((flags & TH_FIN) &&
            sbavail(sb)) {
                /*
                 * We do not transmit a FIN
                 * with data outstanding. We
                 * need to make it so all data
                 * is acked first.
                 */
                flags &= ~TH_FIN;
                if (TCPS_HAVEESTABLISHED(tp->t_state) &&
                    (sbused(sb) == (tp->snd_max - tp->snd_una)) &&
                    ((tp->snd_max - tp->snd_una) <= segsiz)) {
                        /*
                         * Ok less than or right at a MSS is
                         * outstanding. The original FreeBSD stack would
                         * have sent a FIN, which can speed things up for
                         * a transactional application doing a MSG_WAITALL.
                         * To speed things up since we do *not* send a FIN
                         * if data is outstanding, we send a "challenge ack".
                         * The idea behind that is instead of having to have
                         * the peer wait for the delayed-ack timer to run off
                         * we send an ack that makes the peer send us an ack.
                         */
                        rack_send_ack_challange(rack);
                }
        }
        /* Enforce stack imposed max seg size if we have one */
        if (pace_max_seg &&
            (len > pace_max_seg)) {
                mark = 1;
                len = pace_max_seg;
        }
        if ((rsm == NULL) &&
            (rack->pcm_in_progress == 0) &&
            (rack->r_ctl.pcm_max_seg > 0) &&
            (len >= rack->r_ctl.pcm_max_seg)) {
                /* It is large enough for a measurement */
                add_flag |= RACK_IS_PCM;
                rack_log_pcm(rack, 5, len, rack->r_ctl.pcm_max_seg,  add_flag);
        } else if (rack_verbose_logging) {
                rack_log_pcm(rack, 6, len, rack->r_ctl.pcm_max_seg,  add_flag);
        }

        SOCKBUF_LOCK_ASSERT(sb);
        if (len > 0) {
                if (len >= segsiz)
                        tp->t_flags2 |= TF2_PLPMTU_MAXSEGSNT;
                else
                        tp->t_flags2 &= ~TF2_PLPMTU_MAXSEGSNT;
        }
        /*
         * Before ESTABLISHED, force sending of initial options unless TCP
         * set not to do any options. NOTE: we assume that the IP/TCP header
         * plus TCP options always fit in a single mbuf, leaving room for a
         * maximum link header, i.e. max_linkhdr + sizeof (struct tcpiphdr)
         * + optlen <= MCLBYTES
         */
        optlen = 0;
#ifdef INET6
        if (isipv6)
                hdrlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
        else
#endif
                hdrlen = sizeof(struct tcpiphdr);

        /*
         * Ok what seq are we sending from. If we have
         * no rsm to use, then we look at various bits,
         * if we are putting out a SYN it will be ISS.
         * If we are retransmitting a FIN it will
         * be snd_max-1 else its snd_max.
         */
        if (rsm == NULL) {
                if (flags & TH_SYN)
                        rack_seq = tp->iss;
                else if ((flags & TH_FIN) &&
                         (tp->t_flags & TF_SENTFIN))
                        rack_seq = tp->snd_max - 1;
                else
                        rack_seq = tp->snd_max;
        } else {
                rack_seq = rsm->r_start;
        }
        /*
         * Compute options for segment. We only have to care about SYN and
         * established connection segments.  Options for SYN-ACK segments
         * are handled in TCP syncache.
         */
        to.to_flags = 0;
        if ((tp->t_flags & TF_NOOPT) == 0) {
                /* Maximum segment size. */
                if (flags & TH_SYN) {
                        to.to_mss = tcp_mssopt(&inp->inp_inc);
                        if (tp->t_port)
                                to.to_mss -= V_tcp_udp_tunneling_overhead;
                        to.to_flags |= TOF_MSS;

                        /*
                         * On SYN or SYN|ACK transmits on TFO connections,
                         * only include the TFO option if it is not a
                         * retransmit, as the presence of the TFO option may
                         * have caused the original SYN or SYN|ACK to have
                         * been dropped by a middlebox.
                         */
                        if ((tp->t_flags & TF_FASTOPEN) &&
                            (tp->t_rxtshift == 0)) {
                                if (tp->t_state == TCPS_SYN_RECEIVED) {
                                        to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN;
                                        to.to_tfo_cookie =
                                                (u_int8_t *)&tp->t_tfo_cookie.server;
                                        to.to_flags |= TOF_FASTOPEN;
                                        wanted_cookie = 1;
                                } else if (tp->t_state == TCPS_SYN_SENT) {
                                        to.to_tfo_len =
                                                tp->t_tfo_client_cookie_len;
                                        to.to_tfo_cookie =
                                                tp->t_tfo_cookie.client;
                                        to.to_flags |= TOF_FASTOPEN;
                                        wanted_cookie = 1;
                                        /*
                                         * If we wind up having more data to
                                         * send with the SYN than can fit in
                                         * one segment, don't send any more
                                         * until the SYN|ACK comes back from
                                         * the other end.
                                         */
                                        sendalot = 0;
                                }
                        }
                }
                /* Window scaling. */
                if ((flags & TH_SYN) && (tp->t_flags & TF_REQ_SCALE)) {
                        to.to_wscale = tp->request_r_scale;
                        to.to_flags |= TOF_SCALE;
                }
                /* Timestamps. */
                if ((tp->t_flags & TF_RCVD_TSTMP) ||
                    ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) {
                        uint32_t ts_to_use;

                        if ((rack->r_rcvpath_rtt_up == 1) &&
                            (ms_cts == rack->r_ctl.last_rcv_tstmp_for_rtt)) {
                                /*
                                 * When we are doing a rcv_rtt probe all
                                 * other timestamps use the next msec. This
                                 * is safe since our previous ack is in the
                                 * air and we will just have a few more
                                 * on the next ms. This assures that only
                                 * the one ack has the ms_cts that was on
                                 * our ack-probe.
                                 */
                                ts_to_use = ms_cts + 1;
                        } else {
                                ts_to_use = ms_cts;
                        }
                        to.to_tsval = ts_to_use + tp->ts_offset;
                        to.to_tsecr = tp->ts_recent;
                        to.to_flags |= TOF_TS;
                        if ((len == 0) &&
                            (tp->t_state == TCPS_ESTABLISHED) &&
                            ((ms_cts - rack->r_ctl.last_rcv_tstmp_for_rtt) > RCV_PATH_RTT_MS) &&
                            (tp->snd_una == tp->snd_max) &&
                            (flags & TH_ACK) &&
                            (sbavail(sb) == 0) &&
                            (rack->r_ctl.current_round != 0) &&
                            ((flags & (TH_SYN|TH_FIN)) == 0) &&
                            (rack->r_rcvpath_rtt_up == 0)) {
                                rack->r_ctl.last_rcv_tstmp_for_rtt = ms_cts;
                                rack->r_ctl.last_time_of_arm_rcv = cts;
                                rack->r_rcvpath_rtt_up = 1;
                                /* Subtract 1 from seq to force a response */
                                rack_seq--;
                        }
                }
                /* Set receive buffer autosizing timestamp. */
                if (tp->rfbuf_ts == 0 &&
                    (so->so_rcv.sb_flags & SB_AUTOSIZE)) {
                        tp->rfbuf_ts = ms_cts;
                }
                /* Selective ACK's. */
                if (tp->t_flags & TF_SACK_PERMIT) {
                        if (flags & TH_SYN)
                                to.to_flags |= TOF_SACKPERM;
                        else if (TCPS_HAVEESTABLISHED(tp->t_state) &&
                                 tp->rcv_numsacks > 0) {
                                to.to_flags |= TOF_SACK;
                                to.to_nsacks = tp->rcv_numsacks;
                                to.to_sacks = (u_char *)tp->sackblks;
                        }
                }
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
                /* TCP-MD5 (RFC2385). */
                if (tp->t_flags & TF_SIGNATURE)
                        to.to_flags |= TOF_SIGNATURE;
#endif

                /* Processing the options. */
                hdrlen += optlen = tcp_addoptions(&to, opt);
                /*
                 * If we wanted a TFO option to be added, but it was unable
                 * to fit, ensure no data is sent.
                 */
                if ((tp->t_flags & TF_FASTOPEN) && wanted_cookie &&
                    !(to.to_flags & TOF_FASTOPEN))
                        len = 0;
        }
        if (tp->t_port) {
                if (V_tcp_udp_tunneling_port == 0) {
                        /* The port was removed?? */
                        SOCK_SENDBUF_UNLOCK(so);
#ifdef TCP_ACCOUNTING
                        crtsc = get_cyclecount();
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_cnt_counters[SND_OUT_FAIL]++;
                                tp->tcp_proc_time[SND_OUT_FAIL] += (crtsc - ts_val);
                        }
                        sched_unpin();
#endif
                        return (EHOSTUNREACH);
                }
                hdrlen += sizeof(struct udphdr);
        }
#ifdef INET6
        if (isipv6)
                ipoptlen = ip6_optlen(inp);
        else
#endif
                if (inp->inp_options)
                        ipoptlen = inp->inp_options->m_len -
                                offsetof(struct ipoption, ipopt_list);
                else
                        ipoptlen = 0;
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
        ipoptlen += ipsec_optlen;
#endif

        /*
         * Adjust data length if insertion of options will bump the packet
         * length beyond the t_maxseg length. Clear the FIN bit because we
         * cut off the tail of the segment.
         */
        if (len + optlen + ipoptlen > tp->t_maxseg) {
                if (tso) {
                        uint32_t if_hw_tsomax;
                        uint32_t moff;
                        int32_t max_len;

                        /* extract TSO information */
                        if_hw_tsomax = tp->t_tsomax;
                        if_hw_tsomaxsegcount = tp->t_tsomaxsegcount;
                        if_hw_tsomaxsegsize = tp->t_tsomaxsegsize;
                        KASSERT(ipoptlen == 0,
                                ("%s: TSO can't do IP options", __func__));

                        /*
                         * Check if we should limit by maximum payload
                         * length:
                         */
                        if (if_hw_tsomax != 0) {
                                /* compute maximum TSO length */
                                max_len = (if_hw_tsomax - hdrlen -
                                           max_linkhdr);
                                if (max_len <= 0) {
                                        len = 0;
                                } else if (len > max_len) {
                                        if (doing_tlp == 0)
                                                sendalot = 1;
                                        len = max_len;
                                        mark = 2;
                                }
                        }
                        /*
                         * Prevent the last segment from being fractional
                         * unless the send sockbuf can be emptied:
                         */
                        max_len = (tp->t_maxseg - optlen);
                        if ((sb_offset + len) < sbavail(sb)) {
                                moff = len % (u_int)max_len;
                                if (moff != 0) {
                                        mark = 3;
                                        len -= moff;
                                }
                        }
                        /*
                         * In case there are too many small fragments don't
                         * use TSO:
                         */
                        if (len <= max_len) {
                                mark = 4;
                                tso = 0;
                        }
                        /*
                         * Send the FIN in a separate segment after the bulk
                         * sending is done. We don't trust the TSO
                         * implementations to clear the FIN flag on all but
                         * the last segment.
                         */
                        if (tp->t_flags & TF_NEEDFIN) {
                                sendalot = 4;
                        }
                } else {
                        mark = 5;
                        if (optlen + ipoptlen >= tp->t_maxseg) {
                                /*
                                 * Since we don't have enough space to put
                                 * the IP header chain and the TCP header in
                                 * one packet as required by RFC 7112, don't
                                 * send it. Also ensure that at least one
                                 * byte of the payload can be put into the
                                 * TCP segment.
                                 */
                                SOCK_SENDBUF_UNLOCK(so);
                                error = EMSGSIZE;
                                sack_rxmit = 0;
                                goto out;
                        }
                        len = tp->t_maxseg - optlen - ipoptlen;
                        sendalot = 5;
                }
        } else {
                tso = 0;
                mark = 6;
        }
        KASSERT(len + hdrlen + ipoptlen <= IP_MAXPACKET,
                ("%s: len > IP_MAXPACKET", __func__));
#ifdef DIAGNOSTIC
#ifdef INET6
        if (max_linkhdr + hdrlen > MCLBYTES)
#else
                if (max_linkhdr + hdrlen > MHLEN)
#endif
                        panic("tcphdr too big");
#endif

        /*
         * This KASSERT is here to catch edge cases at a well defined place.
         * Before, those had triggered (random) panic conditions further
         * down.
         */
        KASSERT(len >= 0, ("[%s:%d]: len < 0", __func__, __LINE__));
        if ((len == 0) &&
            (flags & TH_FIN) &&
            (sbused(sb))) {
                /*
                 * We have outstanding data, don't send a fin by itself!.
                 *
                 * Check to see if we need to send a challenge ack.
                 */
                if ((sbused(sb) == (tp->snd_max - tp->snd_una)) &&
                    ((tp->snd_max - tp->snd_una) <= segsiz)) {
                        /*
                         * Ok less than or right at a MSS is
                         * outstanding. The original FreeBSD stack would
                         * have sent a FIN, which can speed things up for
                         * a transactional application doing a MSG_WAITALL.
                         * To speed things up since we do *not* send a FIN
                         * if data is outstanding, we send a "challenge ack".
                         * The idea behind that is instead of having to have
                         * the peer wait for the delayed-ack timer to run off
                         * we send an ack that makes the peer send us an ack.
                         */
                        rack_send_ack_challange(rack);
                }
                goto just_return;
        }
        /*
         * Grab a header mbuf, attaching a copy of data to be transmitted,
         * and initialize the header from the template for sends on this
         * connection.
         */
        hw_tls = tp->t_nic_ktls_xmit != 0;
        if (len) {
                uint32_t max_val;
                uint32_t moff;

                if (pace_max_seg)
                        max_val = pace_max_seg;
                else
                        max_val = len;
                /*
                 * We allow a limit on sending with hptsi.
                 */
                if (len > max_val) {
                        mark = 7;
                        len = max_val;
                }
#ifdef INET6
                if (MHLEN < hdrlen + max_linkhdr)
                        m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
                else
#endif
                        m = m_gethdr(M_NOWAIT, MT_DATA);

                if (m == NULL) {
                        SOCK_SENDBUF_UNLOCK(so);
                        error = ENOBUFS;
                        sack_rxmit = 0;
                        goto out;
                }
                m->m_data += max_linkhdr;
                m->m_len = hdrlen;

                /*
                 * Start the m_copy functions from the closest mbuf to the
                 * sb_offset in the socket buffer chain.
                 */
                mb = sbsndptr_noadv(sb, sb_offset, &moff);
                s_mb = mb;
                s_moff = moff;
                if (len <= MHLEN - hdrlen - max_linkhdr && !hw_tls) {
                        m_copydata(mb, moff, (int)len,
                                   mtod(m, caddr_t)+hdrlen);
                        /*
                         * If we are not retransmitting advance the
                         * sndptr to help remember the next place in
                         * the sb.
                         */
                        if (rsm == NULL)
                                sbsndptr_adv(sb, mb, len);
                        m->m_len += len;
                } else {
                        struct sockbuf *msb;

                        /*
                         * If we are not retransmitting pass in msb so
                         * the socket buffer can be advanced. Otherwise
                         * set it to NULL if its a retransmission since
                         * we don't want to change the sb remembered
                         * location.
                         */
                        if (rsm == NULL)
                                msb = sb;
                        else
                                msb = NULL;
                        m->m_next = tcp_m_copym(
                                mb, moff, &len,
                                if_hw_tsomaxsegcount, if_hw_tsomaxsegsize, msb,
                                ((rsm == NULL) ? hw_tls : 0));
                        if (len <= (tp->t_maxseg - optlen)) {
                                /*
                                 * Must have ran out of mbufs for the copy
                                 * shorten it to no longer need tso. Lets
                                 * not put on sendalot since we are low on
                                 * mbufs.
                                 */
                                tso = 0;
                        }
                        if (m->m_next == NULL) {
                                SOCK_SENDBUF_UNLOCK(so);
                                (void)m_free(m);
                                error = ENOBUFS;
                                sack_rxmit = 0;
                                goto out;
                        }
                }
                if (sack_rxmit) {
                        if (rsm && (rsm->r_flags & RACK_TLP)) {
                                /*
                                 * TLP should not count in retran count, but
                                 * in its own bin
                                 */
                                counter_u64_add(rack_tlp_retran, 1);
                                counter_u64_add(rack_tlp_retran_bytes, len);
                        } else {
                                tp->t_sndrexmitpack++;
                                KMOD_TCPSTAT_INC(tcps_sndrexmitpack);
                                KMOD_TCPSTAT_ADD(tcps_sndrexmitbyte, len);
                        }
#ifdef STATS
                        stats_voi_update_abs_u32(tp->t_stats, VOI_TCP_RETXPB,
                                                 len);
#endif
                } else {
                        KMOD_TCPSTAT_INC(tcps_sndpack);
                        KMOD_TCPSTAT_ADD(tcps_sndbyte, len);
#ifdef STATS
                        stats_voi_update_abs_u64(tp->t_stats, VOI_TCP_TXPB,
                                                 len);
#endif
                }
                /*
                 * If we're sending everything we've got, set PUSH. (This
                 * will keep happy those implementations which only give
                 * data to the user when a buffer fills or a PUSH comes in.)
                 */
                if (sb_offset + len == sbused(sb) &&
                    sbused(sb) &&
                    !(flags & TH_SYN)) {
                        flags |= TH_PUSH;
                        add_flag |= RACK_HAD_PUSH;
                }
                SOCK_SENDBUF_UNLOCK(so);
        } else {
                SOCK_SENDBUF_UNLOCK(so);
                if (tp->t_flags & TF_ACKNOW)
                        KMOD_TCPSTAT_INC(tcps_sndacks);
                else if (flags & (TH_SYN | TH_FIN | TH_RST))
                        KMOD_TCPSTAT_INC(tcps_sndctrl);
                else
                        KMOD_TCPSTAT_INC(tcps_sndwinup);

                m = m_gethdr(M_NOWAIT, MT_DATA);
                if (m == NULL) {
                        error = ENOBUFS;
                        sack_rxmit = 0;
                        goto out;
                }
#ifdef INET6
                if (isipv6 && (MHLEN < hdrlen + max_linkhdr) &&
                    MHLEN >= hdrlen) {
                        M_ALIGN(m, hdrlen);
                } else
#endif
                        m->m_data += max_linkhdr;
                m->m_len = hdrlen;
        }
        SOCK_SENDBUF_UNLOCK_ASSERT(so);
        m->m_pkthdr.rcvif = (struct ifnet *)0;
#ifdef MAC
        mac_inpcb_create_mbuf(inp, m);
#endif
        if ((ipoptlen == 0) && (rack->r_ctl.fsb.tcp_ip_hdr) &&  rack->r_fsb_inited) {
#ifdef INET6
                if (isipv6)
                        ip6 = (struct ip6_hdr *)rack->r_ctl.fsb.tcp_ip_hdr;
                else
#endif                          /* INET6 */
#ifdef INET
                        ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr;
#endif
                th = rack->r_ctl.fsb.th;
                udp = rack->r_ctl.fsb.udp;
                if (udp) {
#ifdef INET6
                        if (isipv6)
                                ulen = hdrlen + len - sizeof(struct ip6_hdr);
                        else
#endif                          /* INET6 */
                                ulen = hdrlen + len - sizeof(struct ip);
                        udp->uh_ulen = htons(ulen);
                }
        } else {
#ifdef INET6
                if (isipv6) {
                        ip6 = mtod(m, struct ip6_hdr *);
                        if (tp->t_port) {
                                udp = (struct udphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
                                udp->uh_sport = htons(V_tcp_udp_tunneling_port);
                                udp->uh_dport = tp->t_port;
                                ulen = hdrlen + len - sizeof(struct ip6_hdr);
                                udp->uh_ulen = htons(ulen);
                                th = (struct tcphdr *)(udp + 1);
                        } else
                                th = (struct tcphdr *)(ip6 + 1);
                        tcpip_fillheaders(inp, tp->t_port, ip6, th);
                } else
#endif                          /* INET6 */
                {
#ifdef INET
                        ip = mtod(m, struct ip *);
                        if (tp->t_port) {
                                udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip));
                                udp->uh_sport = htons(V_tcp_udp_tunneling_port);
                                udp->uh_dport = tp->t_port;
                                ulen = hdrlen + len - sizeof(struct ip);
                                udp->uh_ulen = htons(ulen);
                                th = (struct tcphdr *)(udp + 1);
                        } else
                                th = (struct tcphdr *)(ip + 1);
                        tcpip_fillheaders(inp, tp->t_port, ip, th);
#endif
                }
        }
        /*
         * If we are starting a connection, send ECN setup SYN packet. If we
         * are on a retransmit, we may resend those bits a number of times
         * as per RFC 3168.
         */
        if (tp->t_state == TCPS_SYN_SENT && V_tcp_do_ecn) {
                flags |= tcp_ecn_output_syn_sent(tp);
        }
        /* Also handle parallel SYN for ECN */
        if (TCPS_HAVERCVDSYN(tp->t_state) &&
            (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT))) {
                int ect = tcp_ecn_output_established(tp, &flags, len, sack_rxmit);
                if ((tp->t_state == TCPS_SYN_RECEIVED) &&
                    (tp->t_flags2 & TF2_ECN_SND_ECE))
                        tp->t_flags2 &= ~TF2_ECN_SND_ECE;
#ifdef INET6
                if (isipv6) {
                        ip6->ip6_flow &= ~htonl(IPTOS_ECN_MASK << 20);
                        ip6->ip6_flow |= htonl(ect << 20);
                }
                else
#endif
                {
#ifdef INET
                        ip->ip_tos &= ~IPTOS_ECN_MASK;
                        ip->ip_tos |= ect;
#endif
                }
        }
        th->th_seq = htonl(rack_seq);
        th->th_ack = htonl(tp->rcv_nxt);
        tcp_set_flags(th, flags);
        /*
         * Calculate receive window.  Don't shrink window, but avoid silly
         * window syndrome.
         * If a RST segment is sent, advertise a window of zero.
         */
        if (flags & TH_RST) {
                recwin = 0;
        } else {
                if (recwin < (long)(so->so_rcv.sb_hiwat / 4) &&
                    recwin < (long)segsiz) {
                        recwin = 0;
                }
                if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt) &&
                    recwin < (long)(tp->rcv_adv - tp->rcv_nxt))
                        recwin = (long)(tp->rcv_adv - tp->rcv_nxt);
        }

        /*
         * According to RFC1323 the window field in a SYN (i.e., a <SYN> or
         * <SYN,ACK>) segment itself is never scaled.  The <SYN,ACK> case is
         * handled in syncache.
         */
        if (flags & TH_SYN)
                th->th_win = htons((u_short)
                                   (min(sbspace(&so->so_rcv), TCP_MAXWIN)));
        else {
                /* Avoid shrinking window with window scaling. */
                recwin = roundup2(recwin, 1 << tp->rcv_scale);
                th->th_win = htons((u_short)(recwin >> tp->rcv_scale));
        }
        /*
         * Adjust the RXWIN0SENT flag - indicate that we have advertised a 0
         * window.  This may cause the remote transmitter to stall.  This
         * flag tells soreceive() to disable delayed acknowledgements when
         * draining the buffer.  This can occur if the receiver is
         * attempting to read more data than can be buffered prior to
         * transmitting on the connection.
         */
        if (th->th_win == 0) {
                tp->t_sndzerowin++;
                tp->t_flags |= TF_RXWIN0SENT;
        } else
                tp->t_flags &= ~TF_RXWIN0SENT;
        tp->snd_up = tp->snd_una;       /* drag it along, its deprecated */
        /* Now are we using fsb?, if so copy the template data to the mbuf */
        if ((ipoptlen == 0) && (rack->r_ctl.fsb.tcp_ip_hdr) && rack->r_fsb_inited) {
                uint8_t *cpto;

                cpto = mtod(m, uint8_t *);
                memcpy(cpto, rack->r_ctl.fsb.tcp_ip_hdr, rack->r_ctl.fsb.tcp_ip_hdr_len);
                /*
                 * We have just copied in:
                 * IP/IP6
                 * <optional udphdr>
                 * tcphdr (no options)
                 *
                 * We need to grab the correct pointers into the mbuf
                 * for both the tcp header, and possibly the udp header (if tunneling).
                 * We do this by using the offset in the copy buffer and adding it
                 * to the mbuf base pointer (cpto).
                 */
#ifdef INET6
                if (isipv6)
                        ip6 = mtod(m, struct ip6_hdr *);
                else
#endif                          /* INET6 */
#ifdef INET
                        ip = mtod(m, struct ip *);
#endif
                th = (struct tcphdr *)(cpto + ((uint8_t *)rack->r_ctl.fsb.th - rack->r_ctl.fsb.tcp_ip_hdr));
                /* If we have a udp header lets set it into the mbuf as well */
                if (udp)
                        udp = (struct udphdr *)(cpto + ((uint8_t *)rack->r_ctl.fsb.udp - rack->r_ctl.fsb.tcp_ip_hdr));
        }
        if (optlen) {
                bcopy(opt, th + 1, optlen);
                th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
        }
        /*
         * Put TCP length in extended header, and then checksum extended
         * header and data.
         */
        m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */
#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
        if (to.to_flags & TOF_SIGNATURE) {
                /*
                 * Calculate MD5 signature and put it into the place
                 * determined before.
                 * NOTE: since TCP options buffer doesn't point into
                 * mbuf's data, calculate offset and use it.
                 */
                if (!TCPMD5_ENABLED() || TCPMD5_OUTPUT(m, th,
                                                       (u_char *)(th + 1) + (to.to_signature - opt)) != 0) {
                        /*
                         * Do not send segment if the calculation of MD5
                         * digest has failed.
                         */
                        goto out;
                }
        }
#endif
#ifdef INET6
        if (isipv6) {
                /*
                 * ip6_plen is not need to be filled now, and will be filled
                 * in ip6_output.
                 */
                if (tp->t_port) {
                        m->m_pkthdr.csum_flags = CSUM_UDP_IPV6;
                        m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
                        udp->uh_sum = in6_cksum_pseudo(ip6, ulen, IPPROTO_UDP, 0);
                        th->th_sum = htons(0);
                        UDPSTAT_INC(udps_opackets);
                } else {
                        m->m_pkthdr.csum_flags = CSUM_TCP_IPV6;
                        m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
                        th->th_sum = in6_cksum_pseudo(ip6,
                                                      sizeof(struct tcphdr) + optlen + len, IPPROTO_TCP,
                                                      0);
                }
        }
#endif
#if defined(INET6) && defined(INET)
        else
#endif
#ifdef INET
        {
                if (tp->t_port) {
                        m->m_pkthdr.csum_flags = CSUM_UDP;
                        m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
                        udp->uh_sum = in_pseudo(ip->ip_src.s_addr,
                                                ip->ip_dst.s_addr, htons(ulen + IPPROTO_UDP));
                        th->th_sum = htons(0);
                        UDPSTAT_INC(udps_opackets);
                } else {
                        m->m_pkthdr.csum_flags = CSUM_TCP;
                        m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum);
                        th->th_sum = in_pseudo(ip->ip_src.s_addr,
                                               ip->ip_dst.s_addr, htons(sizeof(struct tcphdr) +
                                                                        IPPROTO_TCP + len + optlen));
                }
                /* IP version must be set here for ipv4/ipv6 checking later */
                KASSERT(ip->ip_v == IPVERSION,
                        ("%s: IP version incorrect: %d", __func__, ip->ip_v));
        }
#endif
        /*
         * Enable TSO and specify the size of the segments. The TCP pseudo
         * header checksum is always provided. XXX: Fixme: This is currently
         * not the case for IPv6.
         */
        if (tso) {
                /*
                 * Here we must use t_maxseg and the optlen since
                 * the optlen may include SACK's (or DSACK).
                 */
                KASSERT(len > tp->t_maxseg - optlen,
                        ("%s: len <= tso_segsz", __func__));
                m->m_pkthdr.csum_flags |= CSUM_TSO;
                m->m_pkthdr.tso_segsz = tp->t_maxseg - optlen;
        }
        KASSERT(len + hdrlen == m_length(m, NULL),
                ("%s: mbuf chain different than expected: %d + %u != %u",
                 __func__, len, hdrlen, m_length(m, NULL)));

#ifdef TCP_HHOOK
        /* Run HHOOK_TCP_ESTABLISHED_OUT helper hooks. */
        hhook_run_tcp_est_out(tp, th, &to, len, tso);
#endif
        if ((rack->r_ctl.crte != NULL) &&
            (rack->rc_hw_nobuf == 0) &&
            tcp_bblogging_on(tp)) {
                rack_log_queue_level(tp, rack, len, &tv, cts);
        }
        /* We're getting ready to send; log now. */
        if (tcp_bblogging_on(rack->rc_tp)) {
                union tcp_log_stackspecific log;

                memset(&log, 0, sizeof(log));
                log.u_bbr.inhpts = tcp_in_hpts(rack->rc_tp);
                if (rack->rack_no_prr)
                        log.u_bbr.flex1 = 0;
                else
                        log.u_bbr.flex1 = rack->r_ctl.rc_prr_sndcnt;
                log.u_bbr.flex2 = rack->r_ctl.rc_pace_min_segs;
                log.u_bbr.flex3 = rack->r_ctl.rc_pace_max_segs;
                log.u_bbr.flex4 = orig_len;
                /* Save off the early/late values */
                log.u_bbr.flex6 = rack->r_ctl.rc_agg_early;
                log.u_bbr.applimited = rack->r_ctl.rc_agg_delayed;
                log.u_bbr.bw_inuse = rack_get_bw(rack);
                log.u_bbr.cur_del_rate = rack->r_ctl.gp_bw;
                log.u_bbr.flex8 = 0;
                if (rsm) {
                        if (rsm->r_flags & RACK_RWND_COLLAPSED) {
                                rack_log_collapse(rack, rsm->r_start, rsm->r_end, 0, __LINE__, 5, rsm->r_flags, rsm);
                                counter_u64_add(rack_collapsed_win_rxt, 1);
                                counter_u64_add(rack_collapsed_win_rxt_bytes, (rsm->r_end - rsm->r_start));
                        }
                        if (doing_tlp)
                                log.u_bbr.flex8 = 2;
                        else
                                log.u_bbr.flex8 = 1;
                } else {
                        if (doing_tlp)
                                log.u_bbr.flex8 = 3;
                }
                log.u_bbr.pacing_gain = rack_get_output_gain(rack, rsm);
                log.u_bbr.flex7 = mark;
                log.u_bbr.flex7 <<= 8;
                log.u_bbr.flex7 |= pass;
                log.u_bbr.pkts_out = tp->t_maxseg;
                log.u_bbr.timeStamp = cts;
                log.u_bbr.inflight = ctf_flight_size(rack->rc_tp, rack->r_ctl.rc_sacked);
                if (rsm && (rsm->r_rtr_cnt > 0)) {
                        /*
                         * When we have a retransmit we want to log the
                         * burst at send and flight at send from before.
                         */
                        log.u_bbr.flex5 = rsm->r_fas;
                        log.u_bbr.bbr_substate = rsm->r_bas;
                } else {
                        /*
                         * New transmits we log in flex5 the inflight again as
                         * well as the number of segments in our send in the
                         * substate field.
                         */
                        log.u_bbr.flex5 = log.u_bbr.inflight;
                        log.u_bbr.bbr_substate = (uint8_t)((len + segsiz - 1)/segsiz);
                }
                log.u_bbr.lt_epoch = cwnd_to_use;
                log.u_bbr.delivered = sendalot;
                log.u_bbr.rttProp = (uintptr_t)rsm;
                log.u_bbr.pkt_epoch = __LINE__;
                if (rsm) {
                        log.u_bbr.delRate = rsm->r_flags;
                        log.u_bbr.delRate <<= 31;
                        log.u_bbr.delRate |= rack->r_must_retran;
                        log.u_bbr.delRate <<= 1;
                        log.u_bbr.delRate |= (sack_rxmit & 0x00000001);
                } else {
                        log.u_bbr.delRate = rack->r_must_retran;
                        log.u_bbr.delRate <<= 1;
                        log.u_bbr.delRate |= (sack_rxmit & 0x00000001);
                }
                lgb = tcp_log_event(tp, th, &so->so_rcv, &so->so_snd, TCP_LOG_OUT, ERRNO_UNK,
                                    len, &log, false, NULL, __func__, __LINE__, &tv);
        } else
                lgb = NULL;

        /*
         * Fill in IP length and desired time to live and send to IP level.
         * There should be a better way to handle ttl and tos; we could keep
         * them in the template, but need a way to checksum without them.
         */
        /*
         * m->m_pkthdr.len should have been set before cksum calcuration,
         * because in6_cksum() need it.
         */
#ifdef INET6
        if (isipv6) {
                /*
                 * we separately set hoplimit for every segment, since the
                 * user might want to change the value via setsockopt. Also,
                 * desired default hop limit might be changed via Neighbor
                 * Discovery.
                 */
                rack->r_ctl.fsb.hoplimit = ip6->ip6_hlim = in6_selecthlim(inp, NULL);

                /*
                 * Set the packet size here for the benefit of DTrace
                 * probes. ip6_output() will set it properly; it's supposed
                 * to include the option header lengths as well.
                 */
                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));

                if (V_path_mtu_discovery && tp->t_maxseg > V_tcp_minmss)
                        tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                else
                        tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;

                if (tp->t_state == TCPS_SYN_SENT)
                        TCP_PROBE5(connect__request, NULL, tp, ip6, tp, th);

                TCP_PROBE5(send, NULL, tp, ip6, tp, th);
                /* TODO: IPv6 IP6TOS_ECT bit on */
                error = ip6_output(m,
                                   inp->in6p_outputopts,
                                   &inp->inp_route6,
                                   ((rsm || sack_rxmit) ? IP_NO_SND_TAG_RL : 0),
                                   NULL, NULL, inp);

                if (error == EMSGSIZE && inp->inp_route6.ro_nh != NULL)
                        mtu = inp->inp_route6.ro_nh->nh_mtu;
        }
#endif                          /* INET6 */
#if defined(INET) && defined(INET6)
        else
#endif
#ifdef INET
        {
                ip->ip_len = htons(m->m_pkthdr.len);
#ifdef INET6
                if (inp->inp_vflag & INP_IPV6PROTO)
                        ip->ip_ttl = in6_selecthlim(inp, NULL);
#endif                          /* INET6 */
                rack->r_ctl.fsb.hoplimit = ip->ip_ttl;
                /*
                 * If we do path MTU discovery, then we set DF on every
                 * packet. This might not be the best thing to do according
                 * to RFC3390 Section 2. However the tcp hostcache migitates
                 * the problem so it affects only the first tcp connection
                 * with a host.
                 *
                 * NB: Don't set DF on small MTU/MSS to have a safe
                 * fallback.
                 */
                if (V_path_mtu_discovery && tp->t_maxseg > V_tcp_minmss) {
                        tp->t_flags2 |= TF2_PLPMTU_PMTUD;
                        if (tp->t_port == 0 || len < V_tcp_minmss) {
                                ip->ip_off |= htons(IP_DF);
                        }
                } else {
                        tp->t_flags2 &= ~TF2_PLPMTU_PMTUD;
                }

                if (tp->t_state == TCPS_SYN_SENT)
                        TCP_PROBE5(connect__request, NULL, tp, ip, tp, th);

                TCP_PROBE5(send, NULL, tp, ip, tp, th);

                error = ip_output(m,
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
                                  inp->inp_options,
#else
                                  NULL,
#endif
                                  &inp->inp_route,
                                  ((rsm || sack_rxmit) ? IP_NO_SND_TAG_RL : 0), 0,
                                  inp);
                if (error == EMSGSIZE && inp->inp_route.ro_nh != NULL)
                        mtu = inp->inp_route.ro_nh->nh_mtu;
        }
#endif                          /* INET */
        if (lgb) {
                lgb->tlb_errno = error;
                lgb = NULL;
        }

out:
        /*
         * In transmit state, time the transmission and arrange for the
         * retransmit.  In persist state, just set snd_max.
         */
        if ((rsm == NULL) &&  doing_tlp)
                add_flag |= RACK_TLP;
        rack_log_output(tp, &to, len, rack_seq, (uint8_t) flags, error,
                        rack_to_usec_ts(&tv),
                        rsm, add_flag, s_mb, s_moff, hw_tls, segsiz);
        if (error == 0) {
                if (add_flag & RACK_IS_PCM) {
                        /* We just launched a PCM */
                        /* rrs here log */
                        rack->pcm_in_progress = 1;
                        rack->pcm_needed = 0;
                        rack_log_pcm(rack, 7, len, rack->r_ctl.pcm_max_seg,  add_flag);
                }
                if (rsm == NULL) {
                        if (rack->lt_bw_up == 0) {
                                rack->r_ctl.lt_timemark = tcp_tv_to_lusec(&tv);
                                rack->r_ctl.lt_seq = tp->snd_una;
                                rack->lt_bw_up = 1;
                        } else if (((rack_seq + len) - rack->r_ctl.lt_seq) > 0x7fffffff) {
                                /*
                                 * Need to record what we have since we are
                                 * approaching seq wrap.
                                 */
                                uint64_t tmark;

                                rack->r_ctl.lt_bw_bytes += (tp->snd_una - rack->r_ctl.lt_seq);
                                rack->r_ctl.lt_seq = tp->snd_una;
                                tmark = tcp_get_u64_usecs(&tv);
                                if (tmark > rack->r_ctl.lt_timemark) {
                                        rack->r_ctl.lt_bw_time += (tmark - rack->r_ctl.lt_timemark);
                                        rack->r_ctl.lt_timemark = tmark;
                                }
                        }
                }
                rack->forced_ack = 0;   /* If we send something zap the FA flag */
                counter_u64_add(rack_total_bytes, len);
                tcp_account_for_send(tp, len, (rsm != NULL), doing_tlp, hw_tls);
                if (rsm && doing_tlp) {
                        rack->rc_last_sent_tlp_past_cumack = 0;
                        rack->rc_last_sent_tlp_seq_valid = 1;
                        rack->r_ctl.last_sent_tlp_seq = rsm->r_start;
                        rack->r_ctl.last_sent_tlp_len = rsm->r_end - rsm->r_start;
                }
                if (rack->rc_hw_nobuf) {
                        rack->rc_hw_nobuf = 0;
                        rack->r_ctl.rc_agg_delayed = 0;
                        rack->r_early = 0;
                        rack->r_late = 0;
                        rack->r_ctl.rc_agg_early = 0;
                }
                if (rsm && (doing_tlp == 0)) {
                        /* Set we retransmitted */
                        rack->rc_gp_saw_rec = 1;
                } else {
                        if (cwnd_to_use > tp->snd_ssthresh) {
                                /* Set we sent in CA */
                                rack->rc_gp_saw_ca = 1;
                        } else {
                                /* Set we sent in SS */
                                rack->rc_gp_saw_ss = 1;
                        }
                }
                if (TCPS_HAVEESTABLISHED(tp->t_state) &&
                    (tp->t_flags & TF_SACK_PERMIT) &&
                    tp->rcv_numsacks > 0)
                        tcp_clean_dsack_blocks(tp);
                tot_len_this_send += len;
                if (len == 0) {
                        counter_u64_add(rack_out_size[TCP_MSS_ACCT_SNDACK], 1);
                } else {
                        int idx;

                        idx = (len / segsiz) + 3;
                        if (idx >= TCP_MSS_ACCT_ATIMER)
                                counter_u64_add(rack_out_size[(TCP_MSS_ACCT_ATIMER-1)], 1);
                        else
                                counter_u64_add(rack_out_size[idx], 1);
                }
        }
        if ((rack->rack_no_prr == 0) &&
            sub_from_prr &&
            (error == 0)) {
                if (rack->r_ctl.rc_prr_sndcnt >= len)
                        rack->r_ctl.rc_prr_sndcnt -= len;
                else
                        rack->r_ctl.rc_prr_sndcnt = 0;
        }
        sub_from_prr = 0;
        if (rsm != NULL) {
                if (doing_tlp)
                        /* Make sure the TLP is added */
                        rsm->r_flags |= RACK_TLP;
                else
                        /* If its a resend without TLP then it must not have the flag */
                        rsm->r_flags &= ~RACK_TLP;
        }
        if ((error == 0) &&
            (len > 0) &&
            (tp->snd_una == tp->snd_max))
                rack->r_ctl.rc_tlp_rxt_last_time = cts;

        {
                /*
                 * This block is not associated with the above error == 0 test.
                 * It is used to advance snd_max if we have a new transmit.
                 */
                tcp_seq startseq = tp->snd_max;


                if (rsm && (doing_tlp == 0))
                        rack->r_ctl.rc_loss_count += rsm->r_end - rsm->r_start;
                if (error)
                        /* We don't log or do anything with errors */
                        goto nomore;
                if (doing_tlp == 0) {
                        if (rsm == NULL) {
                                /*
                                 * Not a retransmission of some
                                 * sort, new data is going out so
                                 * clear our TLP count and flag.
                                 */
                                rack->rc_tlp_in_progress = 0;
                                rack->r_ctl.rc_tlp_cnt_out = 0;
                        }
                } else {
                        /*
                         * We have just sent a TLP, mark that it is true
                         * and make sure our in progress is set so we
                         * continue to check the count.
                         */
                        rack->rc_tlp_in_progress = 1;
                        rack->r_ctl.rc_tlp_cnt_out++;
                }
                /*
                 * If we are retransmitting we are done, snd_max
                 * does not get updated.
                 */
                if (sack_rxmit)
                        goto nomore;
                if ((tp->snd_una == tp->snd_max) && (len > 0)) {
                        /*
                         * Update the time we just added data since
                         * nothing was outstanding.
                         */
                        rack_log_progress_event(rack, tp, ticks, PROGRESS_START, __LINE__);
                        tp->t_acktime = ticks;
                }
                /*
                 * Now for special SYN/FIN handling.
                 */
                if (flags & (TH_SYN | TH_FIN)) {
                        if ((flags & TH_SYN) != 0 && tp->snd_max == tp->iss) {
                                tp->snd_max++;
                        }
                        if ((flags & TH_FIN) &&
                            ((tp->t_flags & TF_SENTFIN) == 0)) {
                                tp->snd_max++;
                                tp->t_flags |= TF_SENTFIN;
                        }
                }
                tp->snd_max += len;
                if (rack->rc_new_rnd_needed) {
                        rack_new_round_starts(tp, rack, tp->snd_max);
                }
                /*
                 * Time this transmission if not a retransmission and
                 * not currently timing anything.
                 * This is only relevant in case of switching back to
                 * the base stack.
                 */
                if (tp->t_rtttime == 0) {
                        tp->t_rtttime = ticks;
                        tp->t_rtseq = startseq;
                        KMOD_TCPSTAT_INC(tcps_segstimed);
                }
                if (len &&
                    ((tp->t_flags & TF_GPUTINPROG) == 0))
                        rack_start_gp_measurement(tp, rack, startseq, sb_offset);
                /*
                 * If we are doing FO we need to update the mbuf position and subtract
                 * this happens when the peer sends us duplicate information and
                 * we thus want to send a DSACK.
                 *
                 * XXXRRS: This brings to mind a ?, when we send a DSACK block is TSO
                 * turned off? If not then we are going to echo multiple DSACK blocks
                 * out (with the TSO), which we should not be doing.
                 */
                if (rack->r_fast_output && len) {
                        if (rack->r_ctl.fsb.left_to_send > len)
                                rack->r_ctl.fsb.left_to_send -= len;
                        else
                                rack->r_ctl.fsb.left_to_send = 0;
                        if (rack->r_ctl.fsb.left_to_send < segsiz)
                                rack->r_fast_output = 0;
                        if (rack->r_fast_output) {
                                rack->r_ctl.fsb.m = sbsndmbuf(sb, (tp->snd_max - tp->snd_una), &rack->r_ctl.fsb.off);
                                rack->r_ctl.fsb.o_m_len = rack->r_ctl.fsb.m->m_len;
                                rack->r_ctl.fsb.o_t_len = M_TRAILINGROOM(rack->r_ctl.fsb.m);
                        }
                }
                if (rack_pcm_blast == 0) {
                        if ((orig_len > len) &&
                            (add_flag & RACK_IS_PCM) &&
                            (len < pace_max_seg) &&
                            ((pace_max_seg - len) > segsiz)) {
                                /*
                                 * We are doing a PCM measurement and we did
                                 * not get enough data in the TSO to meet the
                                 * burst requirement.
                                 */
                                uint32_t n_len;

                                n_len = (orig_len - len);
                                orig_len -= len;
                                pace_max_seg -= len;
                                len = n_len;
                                sb_offset = tp->snd_max - tp->snd_una;
                                /* Re-lock for the next spin */
                                SOCK_SENDBUF_LOCK(so);
                                goto send;
                        }
                } else {
                        if ((orig_len > len) &&
                            (add_flag & RACK_IS_PCM) &&
                            ((orig_len - len) > segsiz)) {
                                /*
                                 * We are doing a PCM measurement and we did
                                 * not get enough data in the TSO to meet the
                                 * burst requirement.
                                 */
                                uint32_t n_len;

                                n_len = (orig_len - len);
                                orig_len -= len;
                                len = n_len;
                                sb_offset = tp->snd_max - tp->snd_una;
                                /* Re-lock for the next spin */
                                SOCK_SENDBUF_LOCK(so);
                                goto send;
                        }
                }
        }
nomore:
        if (error) {
                rack->r_ctl.rc_agg_delayed = 0;
                rack->r_early = 0;
                rack->r_late = 0;
                rack->r_ctl.rc_agg_early = 0;
                SOCKBUF_UNLOCK_ASSERT(sb);      /* Check gotos. */
                /*
                 * Failures do not advance the seq counter above. For the
                 * case of ENOBUFS we will fall out and retry in 1ms with
                 * the hpts. Everything else will just have to retransmit
                 * with the timer.
                 *
                 * In any case, we do not want to loop around for another
                 * send without a good reason.
                 */
                sendalot = 0;
                switch (error) {
                case EPERM:
                case EACCES:
                        tp->t_softerror = error;
#ifdef TCP_ACCOUNTING
                        crtsc = get_cyclecount();
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_cnt_counters[SND_OUT_FAIL]++;
                                tp->tcp_proc_time[SND_OUT_FAIL] += (crtsc - ts_val);
                        }
                        sched_unpin();
#endif
                        return (error);
                case ENOBUFS:
                        /*
                         * Pace us right away to retry in a some
                         * time
                         */
                        if (rack->r_ctl.crte != NULL) {
                                tcp_trace_point(rack->rc_tp, TCP_TP_HWENOBUF);
                                if (tcp_bblogging_on(rack->rc_tp))
                                        rack_log_queue_level(tp, rack, len, &tv, cts);
                        } else
                                tcp_trace_point(rack->rc_tp, TCP_TP_ENOBUF);
                        pacing_delay = ((1 + rack->rc_enobuf) * HPTS_USEC_IN_MSEC);
                        if (rack->rc_enobuf < 0x7f)
                                rack->rc_enobuf++;
                        if (pacing_delay < (10 * HPTS_USEC_IN_MSEC))
                                pacing_delay = 10 * HPTS_USEC_IN_MSEC;
                        if (rack->r_ctl.crte != NULL) {
                                counter_u64_add(rack_saw_enobuf_hw, 1);
                                tcp_rl_log_enobuf(rack->r_ctl.crte);
                        }
                        counter_u64_add(rack_saw_enobuf, 1);
                        goto enobufs;
                case EMSGSIZE:
                        /*
                         * For some reason the interface we used initially
                         * to send segments changed to another or lowered
                         * its MTU. If TSO was active we either got an
                         * interface without TSO capabilits or TSO was
                         * turned off. If we obtained mtu from ip_output()
                         * then update it and try again.
                         */
                        if (tso)
                                tp->t_flags &= ~TF_TSO;
                        if (mtu != 0) {
                                int saved_mtu;

                                saved_mtu = tp->t_maxseg;
                                tcp_mss_update(tp, -1, mtu, NULL, NULL);
                                if (saved_mtu > tp->t_maxseg) {
                                        goto again;
                                }
                        }
                        pacing_delay = 10 * HPTS_USEC_IN_MSEC;
                        rack_start_hpts_timer(rack, tp, cts, pacing_delay, 0, 0);
#ifdef TCP_ACCOUNTING
                        crtsc = get_cyclecount();
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_cnt_counters[SND_OUT_FAIL]++;
                                tp->tcp_proc_time[SND_OUT_FAIL] += (crtsc - ts_val);
                        }
                        sched_unpin();
#endif
                        return (error);
                case ENETUNREACH:
                        counter_u64_add(rack_saw_enetunreach, 1);
                        /* FALLTHROUGH */
                case EHOSTDOWN:
                case EHOSTUNREACH:
                case ENETDOWN:
                        if (TCPS_HAVERCVDSYN(tp->t_state)) {
                                tp->t_softerror = error;
                                error = 0;
                        }
                        /* FALLTHROUGH */
                default:
                        pacing_delay = 10 * HPTS_USEC_IN_MSEC;
                        rack_start_hpts_timer(rack, tp, cts, pacing_delay, 0, 0);
#ifdef TCP_ACCOUNTING
                        crtsc = get_cyclecount();
                        if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                                tp->tcp_cnt_counters[SND_OUT_FAIL]++;
                                tp->tcp_proc_time[SND_OUT_FAIL] += (crtsc - ts_val);
                        }
                        sched_unpin();
#endif
                        return (error);
                }
        } else {
                rack->rc_enobuf = 0;
                if (IN_FASTRECOVERY(tp->t_flags) && rsm)
                        rack->r_ctl.retran_during_recovery += len;
        }
        KMOD_TCPSTAT_INC(tcps_sndtotal);

        /*
         * Data sent (as far as we can tell). If this advertises a larger
         * window than any other segment, then remember the size of the
         * advertised window. Any pending ACK has now been sent.
         */
        if (recwin > 0 && SEQ_GT(tp->rcv_nxt + recwin, tp->rcv_adv))
                tp->rcv_adv = tp->rcv_nxt + recwin;

        tp->last_ack_sent = tp->rcv_nxt;
        tp->t_flags &= ~(TF_ACKNOW | TF_DELACK);
enobufs:
        if (sendalot) {
                /* Do we need to turn off sendalot? */
                if (pace_max_seg &&
                    (tot_len_this_send >= pace_max_seg)) {
                        /* We hit our max. */
                        sendalot = 0;
                }
        }
        if ((error == 0) && (flags & TH_FIN))
                tcp_log_end_status(tp, TCP_EI_STATUS_SERVER_FIN);
        if (flags & TH_RST) {
                /*
                 * We don't send again after sending a RST.
                 */
                pacing_delay = 0;
                sendalot = 0;
                if (error == 0)
                        tcp_log_end_status(tp, TCP_EI_STATUS_SERVER_RST);
        } else if ((pacing_delay == 0) && (sendalot == 0) && tot_len_this_send) {
                /*
                 * Get our pacing rate, if an error
                 * occurred in sending (ENOBUF) we would
                 * hit the else if with slot preset. Other
                 * errors return.
                 */
                pacing_delay = rack_get_pacing_delay(rack, tp, tot_len_this_send, rsm, segsiz, __LINE__);
        }
        /* We have sent clear the flag */
        rack->r_ent_rec_ns = 0;
        if (rack->r_must_retran) {
                if (rsm) {
                        rack->r_ctl.rc_out_at_rto -= (rsm->r_end - rsm->r_start);
                        if (SEQ_GEQ(rsm->r_end, rack->r_ctl.rc_snd_max_at_rto)) {
                                /*
                                 * We have retransmitted all.
                                 */
                                rack->r_must_retran = 0;
                                rack->r_ctl.rc_out_at_rto = 0;
                        }
                } else if (SEQ_GEQ(tp->snd_max, rack->r_ctl.rc_snd_max_at_rto)) {
                        /*
                         * Sending new data will also kill
                         * the loop.
                         */
                        rack->r_must_retran = 0;
                        rack->r_ctl.rc_out_at_rto = 0;
                }
        }
        rack->r_ctl.fsb.recwin = recwin;
        if ((tp->t_flags & (TF_WASCRECOVERY|TF_WASFRECOVERY)) &&
            SEQ_GT(tp->snd_max, rack->r_ctl.rc_snd_max_at_rto)) {
                /*
                 * We hit an RTO and now have past snd_max at the RTO
                 * clear all the WAS flags.
                 */
                tp->t_flags &= ~(TF_WASCRECOVERY|TF_WASFRECOVERY);
        }
        if (pacing_delay) {
                /* set the rack tcb into the slot N */
                if ((error == 0) &&
                    rack_use_rfo &&
                    ((flags & (TH_SYN|TH_FIN)) == 0) &&
                    (rsm == NULL) &&
                    (ipoptlen == 0) &&
                    (doing_tlp == 0) &&
                    rack->r_fsb_inited &&
                    TCPS_HAVEESTABLISHED(tp->t_state) &&
                    ((IN_RECOVERY(tp->t_flags)) == 0) &&
                    (rack->r_must_retran == 0) &&
                    ((tp->t_flags & TF_NEEDFIN) == 0) &&
                    (len > 0) && (orig_len > 0) &&
                    (orig_len > len) &&
                    ((orig_len - len) >= segsiz) &&
                    ((optlen == 0) ||
                     ((optlen == TCPOLEN_TSTAMP_APPA) && (to.to_flags & TOF_TS)))) {
                        /* We can send at least one more MSS using our fsb */
                        rack_setup_fast_output(tp, rack, sb, len, orig_len,
                                               segsiz, pace_max_seg, hw_tls, flags);
                } else
                        rack->r_fast_output = 0;
                rack_log_fsb(rack, tp, so, flags,
                             ipoptlen, orig_len, len, error,
                             (rsm == NULL), optlen, __LINE__, 2);
        } else if (sendalot) {
                int ret;

                sack_rxmit = 0;
                if ((error == 0) &&
                    rack_use_rfo &&
                    ((flags & (TH_SYN|TH_FIN)) == 0) &&
                    (rsm == NULL) &&
                    (doing_tlp == 0) &&
                    (ipoptlen == 0) &&
                    (rack->r_must_retran == 0) &&
                    rack->r_fsb_inited &&
                    TCPS_HAVEESTABLISHED(tp->t_state) &&
                    ((IN_RECOVERY(tp->t_flags)) == 0) &&
                    ((tp->t_flags & TF_NEEDFIN) == 0) &&
                    (len > 0) && (orig_len > 0) &&
                    (orig_len > len) &&
                    ((orig_len - len) >= segsiz) &&
                    ((optlen == 0) ||
                     ((optlen == TCPOLEN_TSTAMP_APPA) && (to.to_flags & TOF_TS)))) {
                        /* we can use fast_output for more */
                        rack_setup_fast_output(tp, rack, sb, len, orig_len,
                                               segsiz, pace_max_seg, hw_tls, flags);
                        if (rack->r_fast_output) {
                                error = 0;
                                ret = rack_fast_output(tp, rack, ts_val, cts, ms_cts, &tv, &tot_len_this_send, &error, __LINE__);
                                if (ret >= 0)
                                        return (ret);
                                else if (error)
                                        goto nomore;

                        }
                }
                goto again;
        }
skip_all_send:
        /* Assure when we leave that snd_nxt will point to top */
        if (SEQ_GT(tp->snd_max, tp->snd_nxt))
                tp->snd_nxt = tp->snd_max;
        rack_start_hpts_timer(rack, tp, cts, pacing_delay, tot_len_this_send, 0);
#ifdef TCP_ACCOUNTING
        crtsc = get_cyclecount() - ts_val;
        if (tot_len_this_send) {
                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                        tp->tcp_cnt_counters[SND_OUT_DATA]++;
                        tp->tcp_proc_time[SND_OUT_DATA] += crtsc;
                        tp->tcp_cnt_counters[CNT_OF_MSS_OUT] += ((tot_len_this_send + segsiz - 1) /segsiz);
                }
        } else {
                if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
                        tp->tcp_cnt_counters[SND_OUT_ACK]++;
                        tp->tcp_proc_time[SND_OUT_ACK] += crtsc;
                }
        }
        sched_unpin();
#endif
        if (error == ENOBUFS)
                error = 0;
        return (error);
}

static void
rack_update_seg(struct tcp_rack *rack)
{
        uint32_t orig_val;

        orig_val = rack->r_ctl.rc_pace_max_segs;
        rack_set_pace_segments(rack->rc_tp, rack, __LINE__, NULL);
        if (orig_val != rack->r_ctl.rc_pace_max_segs)
                rack_log_pacing_delay_calc(rack, 0, 0, orig_val, 0, 0, 15, __LINE__, NULL, 0);
}

static void
rack_mtu_change(struct tcpcb *tp)
{
        /*
         * The MSS may have changed
         */
        struct tcp_rack *rack;
        struct rack_sendmap *rsm;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->r_ctl.rc_pace_min_segs != ctf_fixed_maxseg(tp)) {
                /*
                 * The MTU has changed we need to resend everything
                 * since all we have sent is lost. We first fix
                 * up the mtu though.
                 */
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                /* We treat this like a full retransmit timeout without the cwnd adjustment */
                rack_remxt_tmr(tp);
                rack->r_fast_output = 0;
                rack->r_ctl.rc_out_at_rto = ctf_flight_size(tp,
                                                rack->r_ctl.rc_sacked);
                rack->r_ctl.rc_snd_max_at_rto = tp->snd_max;
                rack->r_must_retran = 1;
                /* Mark all inflight to needing to be rxt'd */
                TAILQ_FOREACH(rsm, &rack->r_ctl.rc_tmap, r_tnext) {
                        rsm->r_flags |= (RACK_MUST_RXT|RACK_PMTU_CHG);
                }
        }
        sack_filter_clear(&rack->r_ctl.rack_sf, tp->snd_una);
        /* We don't use snd_nxt to retransmit */
        tp->snd_nxt = tp->snd_max;
}

static int
rack_set_dgp(struct tcp_rack *rack)
{
        if (rack->dgp_on == 1)
                return(0);
        if ((rack->use_fixed_rate == 1) &&
            (rack->rc_always_pace == 1)) {
                /*
                 * We are already pacing another
                 * way.
                 */
                return (EBUSY);
        }
        if (rack->rc_always_pace == 1) {
                rack_remove_pacing(rack);
        }
        if (tcp_incr_dgp_pacing_cnt() == 0)
                return (ENOSPC);
        rack->r_ctl.pacing_method |= RACK_DGP_PACING;
        rack->rc_fillcw_apply_discount = 0;
        rack->dgp_on = 1;
        rack->rc_always_pace = 1;
        rack->rc_pace_dnd = 1;
        rack->use_fixed_rate = 0;
        if (rack->gp_ready)
                rack_set_cc_pacing(rack);
        rack->rc_tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
        rack->rack_attempt_hdwr_pace = 0;
        /* rxt settings */
        rack->full_size_rxt = 1;
        rack->shape_rxt_to_pacing_min  = 0;
        /* cmpack=1 */
        rack->r_use_cmp_ack = 1;
        if (TCPS_HAVEESTABLISHED(rack->rc_tp->t_state) &&
            rack->r_use_cmp_ack)
                rack->rc_tp->t_flags2 |= TF2_MBUF_ACKCMP;
        /* scwnd=1 */
        rack->rack_enable_scwnd = 1;
        /* dynamic=100 */
        rack->rc_gp_dyn_mul = 1;
        /* gp_inc_ca */
        rack->r_ctl.rack_per_of_gp_ca = 100;
        /* rrr_conf=3 */
        rack->r_rr_config = 3;
        /* npush=2 */
        rack->r_ctl.rc_no_push_at_mrtt = 2;
        /* fillcw=1 */
        rack->rc_pace_to_cwnd = 1;
        rack->rc_pace_fill_if_rttin_range = 0;
        rack->rtt_limit_mul = 0;
        /* noprr=1 */
        rack->rack_no_prr = 1;
        /* lscwnd=1 */
        rack->r_limit_scw = 1;
        /* gp_inc_rec */
        rack->r_ctl.rack_per_of_gp_rec = 90;
        return (0);
}

static int
rack_set_profile(struct tcp_rack *rack, int prof)
{
        int err = EINVAL;
        if (prof == 1) {
                /*
                 * Profile 1 is "standard" DGP. It ignores
                 * client buffer level.
                 */
                err = rack_set_dgp(rack);
                if (err)
                        return (err);
        } else if (prof == 6) {
                err = rack_set_dgp(rack);
                if (err)
                        return (err);
                /*
                 * Profile 6 tweaks DGP so that it will apply to
                 * fill-cw the same settings that profile5 does
                 * to replace DGP. It gets then the max(dgp-rate, fillcw(discounted).
                 */
                rack->rc_fillcw_apply_discount = 1;
        } else if (prof == 0) {
                /* This changes things back to the default settings */
                if (rack->rc_always_pace == 1) {
                        rack_remove_pacing(rack);
                } else {
                        /* Make sure any stray flags are off */
                        rack->dgp_on = 0;
                        rack->rc_hybrid_mode = 0;
                        rack->use_fixed_rate = 0;
                }
                err = 0;
                if (rack_fill_cw_state)
                        rack->rc_pace_to_cwnd = 1;
                else
                        rack->rc_pace_to_cwnd = 0;

                if (rack_pace_every_seg && tcp_can_enable_pacing()) {
                        rack->r_ctl.pacing_method |= RACK_REG_PACING;
                        rack->rc_always_pace = 1;
                        if (rack->rack_hibeta)
                                rack_set_cc_pacing(rack);
                } else
                        rack->rc_always_pace = 0;
                if (rack_dsack_std_based & 0x1) {
                        /* Basically this means all rack timers are at least (srtt + 1/4 srtt) */
                        rack->rc_rack_tmr_std_based = 1;
                }
                if (rack_dsack_std_based & 0x2) {
                        /* Basically this means  rack timers are extended based on dsack by up to (2 * srtt) */
                        rack->rc_rack_use_dsack = 1;
                }
                if (rack_use_cmp_acks)
                        rack->r_use_cmp_ack = 1;
                else
                        rack->r_use_cmp_ack = 0;
                if (rack_disable_prr)
                        rack->rack_no_prr = 1;
                else
                        rack->rack_no_prr = 0;
                if (rack_gp_no_rec_chg)
                        rack->rc_gp_no_rec_chg = 1;
                else
                        rack->rc_gp_no_rec_chg = 0;
                if (rack_enable_mqueue_for_nonpaced || rack->r_use_cmp_ack) {
                        rack->r_mbuf_queue = 1;
                        if (TCPS_HAVEESTABLISHED(rack->rc_tp->t_state))
                                rack->rc_tp->t_flags2 |= TF2_MBUF_ACKCMP;
                        rack->rc_tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
                } else {
                        rack->r_mbuf_queue = 0;
                        rack->rc_tp->t_flags2 &= ~TF2_SUPPORTS_MBUFQ;
                }
                if (rack_enable_shared_cwnd)
                        rack->rack_enable_scwnd = 1;
                else
                        rack->rack_enable_scwnd = 0;
                if (rack_do_dyn_mul) {
                        /* When dynamic adjustment is on CA needs to start at 100% */
                        rack->rc_gp_dyn_mul = 1;
                        if (rack_do_dyn_mul >= 100)
                                rack->r_ctl.rack_per_of_gp_ca = rack_do_dyn_mul;
                } else {
                        rack->r_ctl.rack_per_of_gp_ca = rack_per_of_gp_ca;
                        rack->rc_gp_dyn_mul = 0;
                }
                rack->r_rr_config = 0;
                rack->r_ctl.rc_no_push_at_mrtt = 0;
                rack->rc_pace_fill_if_rttin_range = 0;
                rack->rtt_limit_mul = 0;

                if (rack_enable_hw_pacing)
                        rack->rack_hdw_pace_ena = 1;
                else
                        rack->rack_hdw_pace_ena = 0;
                if (rack_disable_prr)
                        rack->rack_no_prr = 1;
                else
                        rack->rack_no_prr = 0;
                if (rack_limits_scwnd)
                        rack->r_limit_scw  = 1;
                else
                        rack->r_limit_scw  = 0;
                rack_init_retransmit_value(rack, rack_rxt_controls);
                err = 0;
        }
        return (err);
}

static int
rack_add_deferred_option(struct tcp_rack *rack, int sopt_name, uint64_t loptval)
{
        struct deferred_opt_list *dol;

        dol = malloc(sizeof(struct deferred_opt_list),
                     M_TCPDO, M_NOWAIT|M_ZERO);
        if (dol == NULL) {
                /*
                 * No space yikes -- fail out..
                 */
                return (0);
        }
        dol->optname = sopt_name;
        dol->optval = loptval;
        TAILQ_INSERT_TAIL(&rack->r_ctl.opt_list, dol, next);
        return (1);
}

static int
process_hybrid_pacing(struct tcp_rack *rack, struct tcp_hybrid_req *hybrid)
{
#ifdef TCP_REQUEST_TRK
        struct tcp_sendfile_track *sft;
        struct timeval tv;
        tcp_seq seq;
        int err;

        microuptime(&tv);

        /* Make sure no fixed rate is on */
        rack->use_fixed_rate = 0;
        rack->r_ctl.rc_fixed_pacing_rate_rec = 0;
        rack->r_ctl.rc_fixed_pacing_rate_ca = 0;
        rack->r_ctl.rc_fixed_pacing_rate_ss = 0;
        /* Now allocate or find our entry that will have these settings */
        sft = tcp_req_alloc_req_full(rack->rc_tp, &hybrid->req, tcp_tv_to_lusec(&tv), 0);
        if (sft == NULL) {
                rack->rc_tp->tcp_hybrid_error++;
                /* no space, where would it have gone? */
                seq = rack->rc_tp->snd_una + rack->rc_tp->t_inpcb.inp_socket->so_snd.sb_ccc;
                rack_log_hybrid(rack, seq, NULL, HYBRID_LOG_NO_ROOM, __LINE__, 0);
                return (ENOSPC);
        }
        /* mask our internal flags */
        hybrid->hybrid_flags &= TCP_HYBRID_PACING_USER_MASK;
        /* The seq will be snd_una + everything in the buffer */
        seq = sft->start_seq;
        if ((hybrid->hybrid_flags & TCP_HYBRID_PACING_ENABLE) == 0) {
                /* Disabling hybrid pacing */
                if (rack->rc_hybrid_mode) {
                        rack_set_profile(rack, 0);
                        rack->rc_tp->tcp_hybrid_stop++;
                }
                rack_log_hybrid(rack, seq, sft, HYBRID_LOG_TURNED_OFF, __LINE__, 0);
                return (0);
        }
        if (rack->dgp_on == 0) {
                /*
                 * If we have not yet turned DGP on, do so
                 * now setting pure DGP mode, no buffer level
                 * response.
                 */
                if ((err = rack_set_profile(rack, 1)) != 0){
                        /* Failed to turn pacing on */
                        rack->rc_tp->tcp_hybrid_error++;
                        rack_log_hybrid(rack, seq, sft, HYBRID_LOG_NO_PACING, __LINE__, 0);
                        return (err);
                }
        }
        /*
         * Now we must switch to hybrid mode as well which also
         * means moving to regular pacing.
         */
        if (rack->rc_hybrid_mode == 0) {
                /* First time */
                if (tcp_can_enable_pacing()) {
                        rack->r_ctl.pacing_method |= RACK_REG_PACING;
                        rack->rc_hybrid_mode = 1;
                } else {
                        return (ENOSPC);
                }
                if (rack->r_ctl.pacing_method & RACK_DGP_PACING) {
                        /*
                         * This should be true.
                         */
                        tcp_dec_dgp_pacing_cnt();
                        rack->r_ctl.pacing_method &= ~RACK_DGP_PACING;
                }
        }
        /* Now set in our flags */
        sft->hybrid_flags = hybrid->hybrid_flags | TCP_HYBRID_PACING_WASSET;
        if (hybrid->hybrid_flags & TCP_HYBRID_PACING_CSPR)
                sft->cspr = hybrid->cspr;
        else
                sft->cspr = 0;
        if (hybrid->hybrid_flags & TCP_HYBRID_PACING_H_MS)
                sft->hint_maxseg = hybrid->hint_maxseg;
        else
                sft->hint_maxseg = 0;
        rack->rc_tp->tcp_hybrid_start++;
        rack_log_hybrid(rack, seq, sft, HYBRID_LOG_RULES_SET, __LINE__,0);
        return (0);
#else
        return (ENOTSUP);
#endif
}

static int
rack_stack_information(struct tcpcb *tp, struct stack_specific_info *si)
{
        /* We pulled a SSI info log out what was there */
        si->bytes_transmitted = tp->t_sndbytes;
        si->bytes_retransmitted = tp->t_snd_rxt_bytes;
        return (0);
}

static int
rack_process_option(struct tcpcb *tp, struct tcp_rack *rack, int sopt_name,
                    uint32_t optval, uint64_t loptval, struct tcp_hybrid_req *hybrid)

{
        struct epoch_tracker et;
        struct sockopt sopt;
        struct cc_newreno_opts opt;
        uint64_t val;
        int error = 0;
        uint16_t ca, ss;

        switch (sopt_name) {
        case TCP_RACK_SET_RXT_OPTIONS:
                if (optval <= 2) {
                        rack_init_retransmit_value(rack, optval);
                } else {
                        /*
                         * You must send in 0, 1 or 2 all else is
                         * invalid.
                         */
                        error = EINVAL;
                }
                break;
        case TCP_RACK_DSACK_OPT:
                RACK_OPTS_INC(tcp_rack_dsack_opt);
                if (optval & 0x1) {
                        rack->rc_rack_tmr_std_based = 1;
                } else {
                        rack->rc_rack_tmr_std_based = 0;
                }
                if (optval & 0x2) {
                        rack->rc_rack_use_dsack = 1;
                } else {
                        rack->rc_rack_use_dsack = 0;
                }
                rack_log_dsack_event(rack, 5, __LINE__, 0, 0);
                break;
        case TCP_RACK_PACING_DIVISOR:
                RACK_OPTS_INC(tcp_rack_pacing_divisor);
                if (optval == 0) {
                        rack->r_ctl.pace_len_divisor = rack_default_pacing_divisor;
                } else {
                        if (optval < RL_MIN_DIVISOR)
                                rack->r_ctl.pace_len_divisor = RL_MIN_DIVISOR;
                        else
                                rack->r_ctl.pace_len_divisor = optval;
                }
                break;
        case TCP_RACK_HI_BETA:
                RACK_OPTS_INC(tcp_rack_hi_beta);
                if (optval > 0) {
                        rack->rack_hibeta = 1;
                        if ((optval >= 50) &&
                            (optval <= 100)) {
                                /*
                                 * User wants to set a custom beta.
                                 */
                                rack->r_ctl.saved_hibeta = optval;
                                if (rack->rc_pacing_cc_set)
                                        rack_undo_cc_pacing(rack);
                                rack->r_ctl.rc_saved_beta = optval;
                        }
                        if (rack->rc_pacing_cc_set == 0)
                                rack_set_cc_pacing(rack);
                } else {
                        rack->rack_hibeta = 0;
                        if (rack->rc_pacing_cc_set)
                                rack_undo_cc_pacing(rack);
                }
                break;
        case TCP_RACK_PACING_BETA:
                error = EINVAL;
                break;
        case TCP_RACK_TIMER_SLOP:
                RACK_OPTS_INC(tcp_rack_timer_slop);
                rack->r_ctl.timer_slop = optval;
                if (rack->rc_tp->t_srtt) {
                        /*
                         * If we have an SRTT lets update t_rxtcur
                         * to have the new slop.
                         */
                        RACK_TCPT_RANGESET(tp->t_rxtcur, RACK_REXMTVAL(tp),
                                           rack_rto_min, rack_rto_max,
                                           rack->r_ctl.timer_slop);
                }
                break;
        case TCP_RACK_PACING_BETA_ECN:
                RACK_OPTS_INC(tcp_rack_beta_ecn);
                if (strcmp(tp->t_cc->name, CCALGONAME_NEWRENO) != 0) {
                        /* This only works for newreno. */
                        error = EINVAL;
                        break;
                }
                if (rack->rc_pacing_cc_set) {
                        /*
                         * Set them into the real CC module
                         * whats in the rack pcb is the old values
                         * to be used on restoral/
                         */
                        sopt.sopt_dir = SOPT_SET;
                        opt.name = CC_NEWRENO_BETA_ECN;
                        opt.val = optval;
                        if (CC_ALGO(tp)->ctl_output != NULL)
                                error = CC_ALGO(tp)->ctl_output(&tp->t_ccv, &sopt, &opt);
                        else
                                error = ENOENT;
                } else {
                        /*
                         * Not pacing yet so set it into our local
                         * rack pcb storage.
                         */
                        rack->r_ctl.rc_saved_beta_ecn = optval;
                }
                break;
        case TCP_DEFER_OPTIONS:
                RACK_OPTS_INC(tcp_defer_opt);
                if (optval) {
                        if (rack->gp_ready) {
                                /* Too late */
                                error = EINVAL;
                                break;
                        }
                        rack->defer_options = 1;
                } else
                        rack->defer_options = 0;
                break;
        case TCP_RACK_MEASURE_CNT:
                RACK_OPTS_INC(tcp_rack_measure_cnt);
                if (optval && (optval <= 0xff)) {
                        rack->r_ctl.req_measurements = optval;
                } else
                        error = EINVAL;
                break;
        case TCP_REC_ABC_VAL:
                RACK_OPTS_INC(tcp_rec_abc_val);
                if (optval > 0)
                        rack->r_use_labc_for_rec = 1;
                else
                        rack->r_use_labc_for_rec = 0;
                break;
        case TCP_RACK_ABC_VAL:
                RACK_OPTS_INC(tcp_rack_abc_val);
                if ((optval > 0) && (optval < 255))
                        rack->rc_labc = optval;
                else
                        error = EINVAL;
                break;
        case TCP_HDWR_UP_ONLY:
                RACK_OPTS_INC(tcp_pacing_up_only);
                if (optval)
                        rack->r_up_only = 1;
                else
                        rack->r_up_only = 0;
                break;
        case TCP_FILLCW_RATE_CAP:               /*  URL:fillcw_cap */
                RACK_OPTS_INC(tcp_fillcw_rate_cap);
                rack->r_ctl.fillcw_cap = loptval;
                break;
        case TCP_PACING_RATE_CAP:
                RACK_OPTS_INC(tcp_pacing_rate_cap);
                if ((rack->dgp_on == 1) &&
                    (rack->r_ctl.pacing_method & RACK_DGP_PACING)) {
                        /*
                         * If we are doing DGP we need to switch
                         * to using the pacing limit.
                         */
                        if (tcp_can_enable_pacing() == 0) {
                                error = ENOSPC;
                                break;
                        }
                        /*
                         * Now change up the flags and counts to be correct.
                         */
                        rack->r_ctl.pacing_method |= RACK_REG_PACING;
                        tcp_dec_dgp_pacing_cnt();
                        rack->r_ctl.pacing_method &= ~RACK_DGP_PACING;
                }
                rack->r_ctl.bw_rate_cap = loptval;
                break;
        case TCP_HYBRID_PACING:
                if (hybrid == NULL) {
                        error = EINVAL;
                        break;
                }
                if (rack->r_ctl.side_chan_dis_mask & HYBRID_DIS_MASK) {
                        error = EPERM;
                        break;
                }
                error = process_hybrid_pacing(rack, hybrid);
                break;
        case TCP_SIDECHAN_DIS:                  /*  URL:scodm */
                if (optval)
                        rack->r_ctl.side_chan_dis_mask = optval;
                else
                        rack->r_ctl.side_chan_dis_mask = 0;
                break;
        case TCP_RACK_PROFILE:
                RACK_OPTS_INC(tcp_profile);
                error = rack_set_profile(rack, optval);
                break;
        case TCP_USE_CMP_ACKS:
                RACK_OPTS_INC(tcp_use_cmp_acks);
                if ((optval == 0) && (tp->t_flags2 & TF2_MBUF_ACKCMP)) {
                        /* You can't turn it off once its on! */
                        error = EINVAL;
                } else if ((optval == 1) && (rack->r_use_cmp_ack == 0)) {
                        rack->r_use_cmp_ack = 1;
                        rack->r_mbuf_queue = 1;
                        tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
                }
                if (rack->r_use_cmp_ack && TCPS_HAVEESTABLISHED(tp->t_state))
                        tp->t_flags2 |= TF2_MBUF_ACKCMP;
                break;
        case TCP_SHARED_CWND_TIME_LIMIT:
                RACK_OPTS_INC(tcp_lscwnd);
                if (optval)
                        rack->r_limit_scw = 1;
                else
                        rack->r_limit_scw = 0;
                break;
        case TCP_RACK_DGP_IN_REC:
                error = EINVAL;
                break;
        case TCP_RACK_PACE_TO_FILL:
                RACK_OPTS_INC(tcp_fillcw);
                if (optval == 0)
                        rack->rc_pace_to_cwnd = 0;
                else {
                        rack->rc_pace_to_cwnd = 1;
                }
                if ((optval >= rack_gp_rtt_maxmul) &&
                    rack_gp_rtt_maxmul &&
                    (optval < 0xf)) {
                        rack->rc_pace_fill_if_rttin_range = 1;
                        rack->rtt_limit_mul = optval;
                } else {
                        rack->rc_pace_fill_if_rttin_range = 0;
                        rack->rtt_limit_mul = 0;
                }
                break;
        case TCP_RACK_NO_PUSH_AT_MAX:
                RACK_OPTS_INC(tcp_npush);
                if (optval == 0)
                        rack->r_ctl.rc_no_push_at_mrtt = 0;
                else if (optval < 0xff)
                        rack->r_ctl.rc_no_push_at_mrtt = optval;
                else
                        error = EINVAL;
                break;
        case TCP_SHARED_CWND_ENABLE:
                RACK_OPTS_INC(tcp_rack_scwnd);
                if (optval == 0)
                        rack->rack_enable_scwnd = 0;
                else
                        rack->rack_enable_scwnd = 1;
                break;
        case TCP_RACK_MBUF_QUEUE:
                /* Now do we use the LRO mbuf-queue feature */
                RACK_OPTS_INC(tcp_rack_mbufq);
                if (optval || rack->r_use_cmp_ack)
                        rack->r_mbuf_queue = 1;
                else
                        rack->r_mbuf_queue = 0;
                if  (rack->r_mbuf_queue || rack->rc_always_pace || rack->r_use_cmp_ack)
                        tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
                else
                        tp->t_flags2 &= ~TF2_SUPPORTS_MBUFQ;
                break;
        case TCP_RACK_NONRXT_CFG_RATE:
                RACK_OPTS_INC(tcp_rack_cfg_rate);
                if (optval == 0)
                        rack->rack_rec_nonrxt_use_cr = 0;
                else
                        rack->rack_rec_nonrxt_use_cr = 1;
                break;
        case TCP_NO_PRR:
                RACK_OPTS_INC(tcp_rack_noprr);
                if (optval == 0)
                        rack->rack_no_prr = 0;
                else if (optval == 1)
                        rack->rack_no_prr = 1;
                else if (optval == 2)
                        rack->no_prr_addback = 1;
                else
                        error = EINVAL;
                break;
        case RACK_CSPR_IS_FCC:                  /*  URL:csprisfcc */
                if (optval > 0)
                        rack->cspr_is_fcc = 1;
                else
                        rack->cspr_is_fcc = 0;
                break;
        case TCP_TIMELY_DYN_ADJ:
                RACK_OPTS_INC(tcp_timely_dyn);
                if (optval == 0)
                        rack->rc_gp_dyn_mul = 0;
                else {
                        rack->rc_gp_dyn_mul = 1;
                        if (optval >= 100) {
                                /*
                                 * If the user sets something 100 or more
                                 * its the gp_ca value.
                                 */
                                rack->r_ctl.rack_per_of_gp_ca  = optval;
                        }
                }
                break;
        case TCP_RACK_DO_DETECTION:
                error = EINVAL;
                break;
        case TCP_RACK_TLP_USE:
                if ((optval < TLP_USE_ID) || (optval > TLP_USE_TWO_TWO)) {
                        error = EINVAL;
                        break;
                }
                RACK_OPTS_INC(tcp_tlp_use);
                rack->rack_tlp_threshold_use = optval;
                break;
        case TCP_RACK_TLP_REDUCE:
                /* RACK TLP cwnd reduction (bool) */
                RACK_OPTS_INC(tcp_rack_tlp_reduce);
                rack->r_ctl.rc_tlp_cwnd_reduce = optval;
                break;
                /*  Pacing related ones */
        case TCP_RACK_PACE_ALWAYS:
                /*
                 * zero is old rack method, 1 is new
                 * method using a pacing rate.
                 */
                RACK_OPTS_INC(tcp_rack_pace_always);
                if (rack->r_ctl.side_chan_dis_mask & CCSP_DIS_MASK) {
                        error = EPERM;
                        break;
                }
                if (optval > 0) {
                        if (rack->rc_always_pace) {
                                error = EALREADY;
                                break;
                        } else if (tcp_can_enable_pacing()) {
                                rack->r_ctl.pacing_method |= RACK_REG_PACING;
                                rack->rc_always_pace = 1;
                                if (rack->rack_hibeta)
                                        rack_set_cc_pacing(rack);
                        }
                        else {
                                error = ENOSPC;
                                break;
                        }
                } else {
                        if (rack->rc_always_pace == 1) {
                                rack_remove_pacing(rack);
                        }
                }
                if  (rack->r_mbuf_queue || rack->rc_always_pace || rack->r_use_cmp_ack)
                        tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
                else
                        tp->t_flags2 &= ~TF2_SUPPORTS_MBUFQ;
                /* A rate may be set irate or other, if so set seg size */
                rack_update_seg(rack);
                break;
        case TCP_BBR_RACK_INIT_RATE:
                RACK_OPTS_INC(tcp_initial_rate);
                val = optval;
                /* Change from kbits per second to bytes per second */
                val *= 1000;
                val /= 8;
                rack->r_ctl.init_rate = val;
                if (rack->rc_always_pace)
                        rack_update_seg(rack);
                break;
        case TCP_BBR_IWINTSO:
                error = EINVAL;
                break;
        case TCP_RACK_FORCE_MSEG:
                RACK_OPTS_INC(tcp_rack_force_max_seg);
                if (optval)
                        rack->rc_force_max_seg = 1;
                else
                        rack->rc_force_max_seg = 0;
                break;
        case TCP_RACK_PACE_MIN_SEG:
                RACK_OPTS_INC(tcp_rack_min_seg);
                rack->r_ctl.rc_user_set_min_segs = (0x0000ffff & optval);
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                break;
        case TCP_RACK_PACE_MAX_SEG:
                /* Max segments size in a pace in bytes */
                RACK_OPTS_INC(tcp_rack_max_seg);
                if ((rack->dgp_on == 1) &&
                    (rack->r_ctl.pacing_method & RACK_DGP_PACING)) {
                        /*
                         * If we set a max-seg and are doing DGP then
                         * we now fall under the pacing limits not the
                         * DGP ones.
                         */
                        if (tcp_can_enable_pacing() == 0) {
                                error = ENOSPC;
                                break;
                        }
                        /*
                         * Now change up the flags and counts to be correct.
                         */
                        rack->r_ctl.pacing_method |= RACK_REG_PACING;
                        tcp_dec_dgp_pacing_cnt();
                        rack->r_ctl.pacing_method &= ~RACK_DGP_PACING;
                }
                if (optval <= MAX_USER_SET_SEG)
                        rack->rc_user_set_max_segs = optval;
                else
                        rack->rc_user_set_max_segs = MAX_USER_SET_SEG;
                rack_set_pace_segments(tp, rack, __LINE__, NULL);
                break;
        case TCP_RACK_PACE_RATE_REC:
                /* Set the fixed pacing rate in Bytes per second ca */
                RACK_OPTS_INC(tcp_rack_pace_rate_rec);
                if (rack->r_ctl.side_chan_dis_mask & CCSP_DIS_MASK) {
                        error = EPERM;
                        break;
                }
                if (rack->dgp_on) {
                        /*
                         * We are already pacing another
                         * way.
                         */
                        error = EBUSY;
                        break;
                }
                rack->r_ctl.rc_fixed_pacing_rate_rec = optval;
                if (rack->r_ctl.rc_fixed_pacing_rate_ca == 0)
                        rack->r_ctl.rc_fixed_pacing_rate_ca = optval;
                if (rack->r_ctl.rc_fixed_pacing_rate_ss == 0)
                        rack->r_ctl.rc_fixed_pacing_rate_ss = optval;
                rack->use_fixed_rate = 1;
                if (rack->rack_hibeta)
                        rack_set_cc_pacing(rack);
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.rc_fixed_pacing_rate_ss,
                                           rack->r_ctl.rc_fixed_pacing_rate_ca,
                                           rack->r_ctl.rc_fixed_pacing_rate_rec, 0, 0, 8,
                                           __LINE__, NULL,0);
                break;

        case TCP_RACK_PACE_RATE_SS:
                /* Set the fixed pacing rate in Bytes per second ca */
                RACK_OPTS_INC(tcp_rack_pace_rate_ss);
                if (rack->r_ctl.side_chan_dis_mask & CCSP_DIS_MASK) {
                        error = EPERM;
                        break;
                }
                if (rack->dgp_on) {
                        /*
                         * We are already pacing another
                         * way.
                         */
                        error = EBUSY;
                        break;
                }
                rack->r_ctl.rc_fixed_pacing_rate_ss = optval;
                if (rack->r_ctl.rc_fixed_pacing_rate_ca == 0)
                        rack->r_ctl.rc_fixed_pacing_rate_ca = optval;
                if (rack->r_ctl.rc_fixed_pacing_rate_rec == 0)
                        rack->r_ctl.rc_fixed_pacing_rate_rec = optval;
                rack->use_fixed_rate = 1;
                if (rack->rack_hibeta)
                        rack_set_cc_pacing(rack);
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.rc_fixed_pacing_rate_ss,
                                           rack->r_ctl.rc_fixed_pacing_rate_ca,
                                           rack->r_ctl.rc_fixed_pacing_rate_rec, 0, 0, 8,
                                           __LINE__, NULL, 0);
                break;

        case TCP_RACK_PACE_RATE_CA:
                /* Set the fixed pacing rate in Bytes per second ca */
                RACK_OPTS_INC(tcp_rack_pace_rate_ca);
                if (rack->r_ctl.side_chan_dis_mask & CCSP_DIS_MASK) {
                        error = EPERM;
                        break;
                }
                if (rack->dgp_on) {
                        /*
                         * We are already pacing another
                         * way.
                         */
                        error = EBUSY;
                        break;
                }
                rack->r_ctl.rc_fixed_pacing_rate_ca = optval;
                if (rack->r_ctl.rc_fixed_pacing_rate_ss == 0)
                        rack->r_ctl.rc_fixed_pacing_rate_ss = optval;
                if (rack->r_ctl.rc_fixed_pacing_rate_rec == 0)
                        rack->r_ctl.rc_fixed_pacing_rate_rec = optval;
                rack->use_fixed_rate = 1;
                if (rack->rack_hibeta)
                        rack_set_cc_pacing(rack);
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.rc_fixed_pacing_rate_ss,
                                           rack->r_ctl.rc_fixed_pacing_rate_ca,
                                           rack->r_ctl.rc_fixed_pacing_rate_rec, 0, 0, 8,
                                           __LINE__, NULL, 0);
                break;
        case TCP_RACK_GP_INCREASE_REC:
                RACK_OPTS_INC(tcp_gp_inc_rec);
                rack->r_ctl.rack_per_of_gp_rec = optval;
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.rack_per_of_gp_ss,
                                           rack->r_ctl.rack_per_of_gp_ca,
                                           rack->r_ctl.rack_per_of_gp_rec, 0, 0, 1,
                                           __LINE__, NULL, 0);
                break;
        case TCP_RACK_GP_INCREASE_CA:
                RACK_OPTS_INC(tcp_gp_inc_ca);
                ca = optval;
                if (ca < 100) {
                        /*
                         * We don't allow any reduction
                         * over the GP b/w.
                         */
                        error = EINVAL;
                        break;
                }
                rack->r_ctl.rack_per_of_gp_ca = ca;
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.rack_per_of_gp_ss,
                                           rack->r_ctl.rack_per_of_gp_ca,
                                           rack->r_ctl.rack_per_of_gp_rec, 0, 0, 1,
                                           __LINE__, NULL, 0);
                break;
        case TCP_RACK_GP_INCREASE_SS:
                RACK_OPTS_INC(tcp_gp_inc_ss);
                ss = optval;
                if (ss < 100) {
                        /*
                         * We don't allow any reduction
                         * over the GP b/w.
                         */
                        error = EINVAL;
                        break;
                }
                rack->r_ctl.rack_per_of_gp_ss = ss;
                rack_log_pacing_delay_calc(rack,
                                           rack->r_ctl.rack_per_of_gp_ss,
                                           rack->r_ctl.rack_per_of_gp_ca,
                                           rack->r_ctl.rack_per_of_gp_rec, 0, 0, 1,
                                           __LINE__, NULL, 0);
                break;
        case TCP_RACK_RR_CONF:
                RACK_OPTS_INC(tcp_rack_rrr_no_conf_rate);
                if (optval && optval <= 3)
                        rack->r_rr_config = optval;
                else
                        rack->r_rr_config = 0;
                break;
        case TCP_PACING_DND:                    /*  URL:dnd */
                if (optval > 0)
                        rack->rc_pace_dnd = 1;
                else
                        rack->rc_pace_dnd = 0;
                break;
        case TCP_HDWR_RATE_CAP:
                RACK_OPTS_INC(tcp_hdwr_rate_cap);
                if (optval) {
                        if (rack->r_rack_hw_rate_caps == 0)
                                rack->r_rack_hw_rate_caps = 1;
                        else
                                error = EALREADY;
                } else {
                        rack->r_rack_hw_rate_caps = 0;
                }
                break;
        case TCP_DGP_UPPER_BOUNDS:
        {
                uint8_t val;
                val = optval & 0x0000ff;
                rack->r_ctl.rack_per_upper_bound_ca = val;
                val = (optval >> 16) & 0x0000ff;
                rack->r_ctl.rack_per_upper_bound_ss = val;
                break;
        }
        case TCP_SS_EEXIT:                      /*  URL:eexit */
                if (optval > 0) {
                        rack->r_ctl.gp_rnd_thresh =  optval & 0x0ff;
                        if (optval & 0x10000) {
                                rack->r_ctl.gate_to_fs = 1;
                        } else {
                                rack->r_ctl.gate_to_fs = 0;
                        }
                        if (optval & 0x20000) {
                                rack->r_ctl.use_gp_not_last = 1;
                        } else {
                                rack->r_ctl.use_gp_not_last = 0;
                        }
                        if (optval & 0xfffc0000) {
                                uint32_t v;

                                v = (optval >> 18) & 0x00003fff;
                                if (v >= 1000)
                                        rack->r_ctl.gp_gain_req = v;
                        }
                } else {
                        /* We do not do ss early exit at all */
                        rack->rc_initial_ss_comp = 1;
                        rack->r_ctl.gp_rnd_thresh = 0;
                }
                break;
        case TCP_RACK_SPLIT_LIMIT:
                RACK_OPTS_INC(tcp_split_limit);
                rack->r_ctl.rc_split_limit = optval;
                break;
        case TCP_BBR_HDWR_PACE:
                RACK_OPTS_INC(tcp_hdwr_pacing);
                if (optval){
                        if (rack->rack_hdrw_pacing == 0) {
                                rack->rack_hdw_pace_ena = 1;
                                rack->rack_attempt_hdwr_pace = 0;
                        } else
                                error = EALREADY;
                } else {
                        rack->rack_hdw_pace_ena = 0;
#ifdef RATELIMIT
                        if (rack->r_ctl.crte != NULL) {
                                rack->rack_hdrw_pacing = 0;
                                rack->rack_attempt_hdwr_pace = 0;
                                tcp_rel_pacing_rate(rack->r_ctl.crte, tp);
                                rack->r_ctl.crte = NULL;
                        }
#endif
                }
                break;
                /*  End Pacing related ones */
        case TCP_RACK_PRR_SENDALOT:
                /* Allow PRR to send more than one seg */
                RACK_OPTS_INC(tcp_rack_prr_sendalot);
                rack->r_ctl.rc_prr_sendalot = optval;
                break;
        case TCP_RACK_MIN_TO:
                /* Minimum time between rack t-o's in ms */
                RACK_OPTS_INC(tcp_rack_min_to);
                rack->r_ctl.rc_min_to = optval;
                break;
        case TCP_RACK_EARLY_SEG:
                /* If early recovery max segments */
                RACK_OPTS_INC(tcp_rack_early_seg);
                rack->r_ctl.rc_early_recovery_segs = optval;
                break;
        case TCP_RACK_ENABLE_HYSTART:
        {
                if (optval) {
                        tp->t_ccv.flags |= CCF_HYSTART_ALLOWED;
                        if (rack_do_hystart > RACK_HYSTART_ON)
                                tp->t_ccv.flags |= CCF_HYSTART_CAN_SH_CWND;
                        if (rack_do_hystart > RACK_HYSTART_ON_W_SC)
                                tp->t_ccv.flags |= CCF_HYSTART_CONS_SSTH;
                } else {
                        tp->t_ccv.flags &= ~(CCF_HYSTART_ALLOWED|CCF_HYSTART_CAN_SH_CWND|CCF_HYSTART_CONS_SSTH);
                }
        }
        break;
        case TCP_RACK_REORD_THRESH:
                /* RACK reorder threshold (shift amount) */
                RACK_OPTS_INC(tcp_rack_reord_thresh);
                if ((optval > 0) && (optval < 31))
                        rack->r_ctl.rc_reorder_shift = optval;
                else
                        error = EINVAL;
                break;
        case TCP_RACK_REORD_FADE:
                /* Does reordering fade after ms time */
                RACK_OPTS_INC(tcp_rack_reord_fade);
                rack->r_ctl.rc_reorder_fade = optval;
                break;
        case TCP_RACK_TLP_THRESH:
                /* RACK TLP theshold i.e. srtt+(srtt/N) */
                RACK_OPTS_INC(tcp_rack_tlp_thresh);
                if (optval)
                        rack->r_ctl.rc_tlp_threshold = optval;
                else
                        error = EINVAL;
                break;
        case TCP_BBR_USE_RACK_RR:
                RACK_OPTS_INC(tcp_rack_rr);
                if (optval)
                        rack->use_rack_rr = 1;
                else
                        rack->use_rack_rr = 0;
                break;
        case TCP_RACK_PKT_DELAY:
                /* RACK added ms i.e. rack-rtt + reord + N */
                RACK_OPTS_INC(tcp_rack_pkt_delay);
                rack->r_ctl.rc_pkt_delay = optval;
                break;
        case TCP_DELACK:
                RACK_OPTS_INC(tcp_rack_delayed_ack);
                if (optval == 0)
                        tp->t_delayed_ack = 0;
                else
                        tp->t_delayed_ack = 1;
                if (tp->t_flags & TF_DELACK) {
                        tp->t_flags &= ~TF_DELACK;
                        tp->t_flags |= TF_ACKNOW;
                        NET_EPOCH_ENTER(et);
                        rack_output(tp);
                        NET_EPOCH_EXIT(et);
                }
                break;

        case TCP_BBR_RACK_RTT_USE:
                RACK_OPTS_INC(tcp_rack_rtt_use);
                if ((optval != USE_RTT_HIGH) &&
                    (optval != USE_RTT_LOW) &&
                    (optval != USE_RTT_AVG))
                        error = EINVAL;
                else
                        rack->r_ctl.rc_rate_sample_method = optval;
                break;
        case TCP_HONOR_HPTS_MIN:
                RACK_OPTS_INC(tcp_honor_hpts);
                if (optval) {
                        rack->r_use_hpts_min = 1;
                        /*
                         * Must be between 2 - 80% to be a reduction else
                         * we keep the default (10%).
                         */
                        if ((optval > 1) && (optval <= 80)) {
                                rack->r_ctl.max_reduction = optval;
                        }
                } else
                        rack->r_use_hpts_min = 0;
                break;
        case TCP_REC_IS_DYN:                    /*  URL:dynrec */
                RACK_OPTS_INC(tcp_dyn_rec);
                if (optval)
                        rack->rc_gp_no_rec_chg = 1;
                else
                        rack->rc_gp_no_rec_chg = 0;
                break;
        case TCP_NO_TIMELY:
                RACK_OPTS_INC(tcp_notimely);
                if (optval) {
                        rack->rc_skip_timely = 1;
                        rack->r_ctl.rack_per_of_gp_rec = 90;
                        rack->r_ctl.rack_per_of_gp_ca = 100;
                        rack->r_ctl.rack_per_of_gp_ss = 250;
                } else {
                        rack->rc_skip_timely = 0;
                }
                break;
        case TCP_GP_USE_LTBW:
                if (optval == 0) {
                        rack->use_lesser_lt_bw = 0;
                        rack->dis_lt_bw = 1;
                } else if (optval == 1) {
                        rack->use_lesser_lt_bw = 1;
                        rack->dis_lt_bw = 0;
                } else if (optval == 2) {
                        rack->use_lesser_lt_bw = 0;
                        rack->dis_lt_bw = 0;
                }
                break;
        case TCP_DATA_AFTER_CLOSE:
                RACK_OPTS_INC(tcp_data_after_close);
                if (optval)
                        rack->rc_allow_data_af_clo = 1;
                else
                        rack->rc_allow_data_af_clo = 0;
                break;
        default:
                break;
        }
        tcp_log_socket_option(tp, sopt_name, optval, error);
        return (error);
}

static void
rack_inherit(struct tcpcb *tp, struct inpcb *parent)
{
        /*
         * A new connection has been created (tp) and
         * the parent is the inpcb given. We want to
         * apply a read-lock to the parent (we are already
         * holding a write lock on the tp) and copy anything
         * out of the rack specific data as long as its tfb is
         * the same as ours i.e. we are the same stack. Otherwise
         * we just return.
         */
        struct tcpcb *par;
        struct tcp_rack *dest, *src;
        int cnt = 0;

        par = intotcpcb(parent);
        if (par->t_fb != tp->t_fb) {
                /* Not the same stack */
                tcp_log_socket_option(tp, 0, 0, 1);
                return;
        }
        /* Ok if we reach here lets setup the two rack pointers */
        dest = (struct tcp_rack *)tp->t_fb_ptr;
        src = (struct tcp_rack *)par->t_fb_ptr;
        if ((src == NULL) || (dest == NULL)) {
                /* Huh? */
                tcp_log_socket_option(tp, 0, 0, 2);
                return;
        }
        /* Now copy out anything we wish to inherit i.e. things in socket-options */
        /* TCP_RACK_PROFILE we can't know but we can set DGP if its on */
        if ((src->dgp_on) && (dest->dgp_on == 0)) {
                /* Profile 1 had to be set via sock opt */
                rack_set_dgp(dest);
                cnt++;
        }
        /* TCP_RACK_SET_RXT_OPTIONS */
        if (dest->full_size_rxt != src->full_size_rxt) {
                dest->full_size_rxt = src->full_size_rxt;
                cnt++;
        }
        if (dest->shape_rxt_to_pacing_min  != src->shape_rxt_to_pacing_min) {
                dest->shape_rxt_to_pacing_min = src->shape_rxt_to_pacing_min;
                cnt++;
        }
        /* TCP_RACK_DSACK_OPT */
        if (dest->rc_rack_tmr_std_based != src->rc_rack_tmr_std_based) {
                dest->rc_rack_tmr_std_based = src->rc_rack_tmr_std_based;
                cnt++;
        }
        if (dest->rc_rack_use_dsack != src->rc_rack_use_dsack) {
                dest->rc_rack_use_dsack = src->rc_rack_use_dsack;
                cnt++;
        }
        /* TCP_RACK_PACING_DIVISOR */
        if (dest->r_ctl.pace_len_divisor != src->r_ctl.pace_len_divisor) {
                dest->r_ctl.pace_len_divisor = src->r_ctl.pace_len_divisor;
                cnt++;
        }
        /* TCP_RACK_HI_BETA */
        if (src->rack_hibeta != dest->rack_hibeta) {
                cnt++;
                if (src->rack_hibeta) {
                        dest->r_ctl.rc_saved_beta = src->r_ctl.rc_saved_beta;
                        dest->rack_hibeta = 1;
                } else {
                        dest->rack_hibeta = 0;
                }
        }
        /* TCP_RACK_TIMER_SLOP */
        if (dest->r_ctl.timer_slop != src->r_ctl.timer_slop) {
                dest->r_ctl.timer_slop = src->r_ctl.timer_slop;
                cnt++;
        }
        /* TCP_RACK_PACING_BETA_ECN */
        if (dest->r_ctl.rc_saved_beta_ecn != src->r_ctl.rc_saved_beta_ecn) {
                dest->r_ctl.rc_saved_beta_ecn = src->r_ctl.rc_saved_beta_ecn;
                cnt++;
        }
        /* We do not do TCP_DEFER_OPTIONS */
        /* TCP_RACK_MEASURE_CNT */
        if (dest->r_ctl.req_measurements != src->r_ctl.req_measurements) {
                dest->r_ctl.req_measurements = src->r_ctl.req_measurements;
                cnt++;
        }
        /* TCP_HDWR_UP_ONLY */
        if (dest->r_up_only != src->r_up_only) {
                dest->r_up_only = src->r_up_only;
                cnt++;
        }
        /* TCP_FILLCW_RATE_CAP */
        if (dest->r_ctl.fillcw_cap != src->r_ctl.fillcw_cap) {
                dest->r_ctl.fillcw_cap = src->r_ctl.fillcw_cap;
                cnt++;
        }
        /* TCP_PACING_RATE_CAP */
        if (dest->r_ctl.bw_rate_cap != src->r_ctl.bw_rate_cap) {
                dest->r_ctl.bw_rate_cap = src->r_ctl.bw_rate_cap;
                cnt++;
        }
        /* A listener can't set TCP_HYBRID_PACING */
        /* TCP_SIDECHAN_DIS */
        if (dest->r_ctl.side_chan_dis_mask != src->r_ctl.side_chan_dis_mask) {
                dest->r_ctl.side_chan_dis_mask = src->r_ctl.side_chan_dis_mask;
                cnt++;
        }
        /* TCP_SHARED_CWND_TIME_LIMIT */
        if (dest->r_limit_scw != src->r_limit_scw) {
                dest->r_limit_scw = src->r_limit_scw;
                cnt++;
        }
        /* TCP_RACK_PACE_TO_FILL */
        if (dest->rc_pace_to_cwnd != src->rc_pace_to_cwnd) {
                dest->rc_pace_to_cwnd = src->rc_pace_to_cwnd;
                cnt++;
        }
        if (dest->rc_pace_fill_if_rttin_range != src->rc_pace_fill_if_rttin_range) {
                dest->rc_pace_fill_if_rttin_range = src->rc_pace_fill_if_rttin_range;
                cnt++;
        }
        if (dest->rtt_limit_mul != src->rtt_limit_mul) {
                dest->rtt_limit_mul = src->rtt_limit_mul;
                cnt++;
        }
        /* TCP_RACK_NO_PUSH_AT_MAX */
        if (dest->r_ctl.rc_no_push_at_mrtt != src->r_ctl.rc_no_push_at_mrtt) {
                dest->r_ctl.rc_no_push_at_mrtt = src->r_ctl.rc_no_push_at_mrtt;
                cnt++;
        }
        /* TCP_SHARED_CWND_ENABLE */
        if (dest->rack_enable_scwnd != src->rack_enable_scwnd) {
                dest->rack_enable_scwnd = src->rack_enable_scwnd;
                cnt++;
        }
        /* TCP_USE_CMP_ACKS */
        if (dest->r_use_cmp_ack != src->r_use_cmp_ack) {
                dest->r_use_cmp_ack = src->r_use_cmp_ack;
                cnt++;
        }

        if (dest->r_mbuf_queue != src->r_mbuf_queue) {
                dest->r_mbuf_queue = src->r_mbuf_queue;
                cnt++;
        }
        /* TCP_RACK_MBUF_QUEUE */
        if (dest->r_mbuf_queue != src->r_mbuf_queue) {
                dest->r_mbuf_queue = src->r_mbuf_queue;
                cnt++;
        }
        if  (dest->r_mbuf_queue || dest->rc_always_pace || dest->r_use_cmp_ack) {
                tp->t_flags2 |= TF2_SUPPORTS_MBUFQ;
        } else {
                tp->t_flags2 &= ~TF2_SUPPORTS_MBUFQ;
        }
        if (dest->r_use_cmp_ack && TCPS_HAVEESTABLISHED(tp->t_state)) {
                tp->t_flags2 |= TF2_MBUF_ACKCMP;
        }
        /* TCP_RACK_NONRXT_CFG_RATE */
        if (dest->rack_rec_nonrxt_use_cr != src->rack_rec_nonrxt_use_cr) {
                dest->rack_rec_nonrxt_use_cr = src->rack_rec_nonrxt_use_cr;
                cnt++;
        }
        /* TCP_NO_PRR */
        if (dest->rack_no_prr != src->rack_no_prr) {
                dest->rack_no_prr = src->rack_no_prr;
                cnt++;
        }
        if (dest->no_prr_addback != src->no_prr_addback) {
                dest->no_prr_addback = src->no_prr_addback;
                cnt++;
        }
        /* RACK_CSPR_IS_FCC */
        if (dest->cspr_is_fcc != src->cspr_is_fcc) {
                dest->cspr_is_fcc = src->cspr_is_fcc;
                cnt++;
        }
        /* TCP_TIMELY_DYN_ADJ */
        if (dest->rc_gp_dyn_mul != src->rc_gp_dyn_mul) {
                dest->rc_gp_dyn_mul = src->rc_gp_dyn_mul;
                cnt++;
        }
        if (dest->r_ctl.rack_per_of_gp_ca != src->r_ctl.rack_per_of_gp_ca) {
                dest->r_ctl.rack_per_of_gp_ca = src->r_ctl.rack_per_of_gp_ca;
                cnt++;
        }
        /* TCP_RACK_TLP_USE */
        if (dest->rack_tlp_threshold_use != src->rack_tlp_threshold_use) {
                dest->rack_tlp_threshold_use = src->rack_tlp_threshold_use;
                cnt++;
        }
        /* we don't allow inheritence of TCP_RACK_PACE_ALWAYS */
        /* TCP_BBR_RACK_INIT_RATE */
        if (dest->r_ctl.init_rate != src->r_ctl.init_rate) {
                dest->r_ctl.init_rate = src->r_ctl.init_rate;
                cnt++;
        }
        /* TCP_RACK_FORCE_MSEG */
        if (dest->rc_force_max_seg != src->rc_force_max_seg) {
                dest->rc_force_max_seg = src->rc_force_max_seg;
                cnt++;
        }
        /* TCP_RACK_PACE_MIN_SEG */
        if (dest->r_ctl.rc_user_set_min_segs != src->r_ctl.rc_user_set_min_segs) {
                dest->r_ctl.rc_user_set_min_segs = src->r_ctl.rc_user_set_min_segs;
                cnt++;
        }
        /* we don't allow TCP_RACK_PACE_MAX_SEG */
        /* TCP_RACK_PACE_RATE_REC, TCP_RACK_PACE_RATE_SS,  TCP_RACK_PACE_RATE_CA */
        if (dest->r_ctl.rc_fixed_pacing_rate_ca != src->r_ctl.rc_fixed_pacing_rate_ca) {
                dest->r_ctl.rc_fixed_pacing_rate_ca = src->r_ctl.rc_fixed_pacing_rate_ca;
                cnt++;
        }
        if (dest->r_ctl.rc_fixed_pacing_rate_ss != src->r_ctl.rc_fixed_pacing_rate_ss) {
                dest->r_ctl.rc_fixed_pacing_rate_ss = src->r_ctl.rc_fixed_pacing_rate_ss;
                cnt++;
        }
        if (dest->r_ctl.rc_fixed_pacing_rate_rec != src->r_ctl.rc_fixed_pacing_rate_rec) {
                dest->r_ctl.rc_fixed_pacing_rate_rec = src->r_ctl.rc_fixed_pacing_rate_rec;
                cnt++;
        }
        /* TCP_RACK_GP_INCREASE_REC, TCP_RACK_GP_INCREASE_CA, TCP_RACK_GP_INCREASE_SS */
        if (dest->r_ctl.rack_per_of_gp_rec != src->r_ctl.rack_per_of_gp_rec) {
                dest->r_ctl.rack_per_of_gp_rec = src->r_ctl.rack_per_of_gp_rec;
                cnt++;
        }
        if (dest->r_ctl.rack_per_of_gp_ca != src->r_ctl.rack_per_of_gp_ca) {
                dest->r_ctl.rack_per_of_gp_ca = src->r_ctl.rack_per_of_gp_ca;
                cnt++;
        }

        if (dest->r_ctl.rack_per_of_gp_ss != src->r_ctl.rack_per_of_gp_ss) {
                dest->r_ctl.rack_per_of_gp_ss = src->r_ctl.rack_per_of_gp_ss;
                cnt++;
        }
        /* TCP_RACK_RR_CONF */
        if (dest->r_rr_config != src->r_rr_config) {
                dest->r_rr_config = src->r_rr_config;
                cnt++;
        }
        /* TCP_PACING_DND */
        if (dest->rc_pace_dnd != src->rc_pace_dnd) {
                dest->rc_pace_dnd = src->rc_pace_dnd;
                cnt++;
        }
        /* TCP_HDWR_RATE_CAP */
        if (dest->r_rack_hw_rate_caps != src->r_rack_hw_rate_caps) {
                dest->r_rack_hw_rate_caps = src->r_rack_hw_rate_caps;
                cnt++;
        }
        /* TCP_DGP_UPPER_BOUNDS */
        if (dest->r_ctl.rack_per_upper_bound_ca != src->r_ctl.rack_per_upper_bound_ca) {
                dest->r_ctl.rack_per_upper_bound_ca = src->r_ctl.rack_per_upper_bound_ca;
                cnt++;
        }
        if (dest->r_ctl.rack_per_upper_bound_ss != src->r_ctl.rack_per_upper_bound_ss) {
                dest->r_ctl.rack_per_upper_bound_ss = src->r_ctl.rack_per_upper_bound_ss;
                cnt++;
        }
        /* TCP_SS_EEXIT */
        if (dest->r_ctl.gp_rnd_thresh != src->r_ctl.gp_rnd_thresh) {
                dest->r_ctl.gp_rnd_thresh = src->r_ctl.gp_rnd_thresh;
                cnt++;
        }
        if (dest->r_ctl.gate_to_fs != src->r_ctl.gate_to_fs) {
                dest->r_ctl.gate_to_fs = src->r_ctl.gate_to_fs;
                cnt++;
        }
        if (dest->r_ctl.use_gp_not_last != src->r_ctl.use_gp_not_last) {
                dest->r_ctl.use_gp_not_last = src->r_ctl.use_gp_not_last;
                cnt++;
        }
        if (dest->r_ctl.gp_gain_req != src->r_ctl.gp_gain_req) {
                dest->r_ctl.gp_gain_req = src->r_ctl.gp_gain_req;
                cnt++;
        }
        /* TCP_BBR_HDWR_PACE */
        if (dest->rack_hdw_pace_ena != src->rack_hdw_pace_ena) {
                dest->rack_hdw_pace_ena = src->rack_hdw_pace_ena;
                cnt++;
        }
        if (dest->rack_attempt_hdwr_pace != src->rack_attempt_hdwr_pace) {
                dest->rack_attempt_hdwr_pace = src->rack_attempt_hdwr_pace;
                cnt++;
        }
        /* TCP_RACK_PRR_SENDALOT */
        if (dest->r_ctl.rc_prr_sendalot != src->r_ctl.rc_prr_sendalot) {
                dest->r_ctl.rc_prr_sendalot = src->r_ctl.rc_prr_sendalot;
                cnt++;
        }
        /* TCP_RACK_MIN_TO */
        if (dest->r_ctl.rc_min_to != src->r_ctl.rc_min_to) {
                dest->r_ctl.rc_min_to = src->r_ctl.rc_min_to;
                cnt++;
        }
        /* TCP_RACK_EARLY_SEG */
        if (dest->r_ctl.rc_early_recovery_segs != src->r_ctl.rc_early_recovery_segs) {
                dest->r_ctl.rc_early_recovery_segs = src->r_ctl.rc_early_recovery_segs;
                cnt++;
        }
        /* TCP_RACK_ENABLE_HYSTART */
        if (par->t_ccv.flags != tp->t_ccv.flags) {
                cnt++;
                if (par->t_ccv.flags & CCF_HYSTART_ALLOWED) {
                        tp->t_ccv.flags |= CCF_HYSTART_ALLOWED;
                        if (rack_do_hystart > RACK_HYSTART_ON)
                                tp->t_ccv.flags |= CCF_HYSTART_CAN_SH_CWND;
                        if (rack_do_hystart > RACK_HYSTART_ON_W_SC)
                                tp->t_ccv.flags |= CCF_HYSTART_CONS_SSTH;
                } else {
                        tp->t_ccv.flags &= ~(CCF_HYSTART_ALLOWED|CCF_HYSTART_CAN_SH_CWND|CCF_HYSTART_CONS_SSTH);
                }
        }
        /* TCP_RACK_REORD_THRESH */
        if (dest->r_ctl.rc_reorder_shift != src->r_ctl.rc_reorder_shift) {
                dest->r_ctl.rc_reorder_shift = src->r_ctl.rc_reorder_shift;
                cnt++;
        }
        /* TCP_RACK_REORD_FADE */
        if (dest->r_ctl.rc_reorder_fade != src->r_ctl.rc_reorder_fade) {
                dest->r_ctl.rc_reorder_fade = src->r_ctl.rc_reorder_fade;
                cnt++;
        }
        /* TCP_RACK_TLP_THRESH */
        if (dest->r_ctl.rc_tlp_threshold != src->r_ctl.rc_tlp_threshold) {
                dest->r_ctl.rc_tlp_threshold = src->r_ctl.rc_tlp_threshold;
                cnt++;
        }
        /* TCP_BBR_USE_RACK_RR */
        if (dest->use_rack_rr != src->use_rack_rr) {
                dest->use_rack_rr = src->use_rack_rr;
                cnt++;
        }
        /* TCP_RACK_PKT_DELAY */
        if (dest->r_ctl.rc_pkt_delay != src->r_ctl.rc_pkt_delay) {
                dest->r_ctl.rc_pkt_delay = src->r_ctl.rc_pkt_delay;
                cnt++;
        }
        /* TCP_DELACK will get copied via the main code if applicable */
        /* TCP_BBR_RACK_RTT_USE */
        if (dest->r_ctl.rc_rate_sample_method != src->r_ctl.rc_rate_sample_method) {
                dest->r_ctl.rc_rate_sample_method = src->r_ctl.rc_rate_sample_method;
                cnt++;
        }
        /* TCP_HONOR_HPTS_MIN */
        if (dest->r_use_hpts_min != src->r_use_hpts_min) {
                dest->r_use_hpts_min = src->r_use_hpts_min;
                cnt++;
        }
        if (dest->r_ctl.max_reduction != src->r_ctl.max_reduction) {
                dest->r_ctl.max_reduction = src->r_ctl.max_reduction;
                cnt++;
        }
        /* TCP_REC_IS_DYN */
        if (dest->rc_gp_no_rec_chg != src->rc_gp_no_rec_chg) {
                dest->rc_gp_no_rec_chg = src->rc_gp_no_rec_chg;
                cnt++;
        }
        if (dest->rc_skip_timely != src->rc_skip_timely) {
                dest->rc_skip_timely = src->rc_skip_timely;
                cnt++;
        }
        /* TCP_DATA_AFTER_CLOSE */
        if (dest->rc_allow_data_af_clo != src->rc_allow_data_af_clo) {
                dest->rc_allow_data_af_clo = src->rc_allow_data_af_clo;
                cnt++;
        }
        /* TCP_GP_USE_LTBW */
        if (src->use_lesser_lt_bw != dest->use_lesser_lt_bw) {
                dest->use_lesser_lt_bw = src->use_lesser_lt_bw;
                cnt++;
        }
        if (dest->dis_lt_bw != src->dis_lt_bw) {
                dest->dis_lt_bw = src->dis_lt_bw;
                cnt++;
        }
        tcp_log_socket_option(tp, 0, cnt, 0);
}


static void
rack_apply_deferred_options(struct tcp_rack *rack)
{
        struct deferred_opt_list *dol, *sdol;
        uint32_t s_optval;

        TAILQ_FOREACH_SAFE(dol, &rack->r_ctl.opt_list, next, sdol) {
                TAILQ_REMOVE(&rack->r_ctl.opt_list, dol, next);
                /* Disadvantage of deferal is you loose the error return */
                s_optval = (uint32_t)dol->optval;
                (void)rack_process_option(rack->rc_tp, rack, dol->optname, s_optval, dol->optval, NULL);
                free(dol, M_TCPDO);
        }
}

static void
rack_hw_tls_change(struct tcpcb *tp, int chg)
{
        /* Update HW tls state */
        struct tcp_rack *rack;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (chg)
                rack->r_ctl.fsb.hw_tls = 1;
        else
                rack->r_ctl.fsb.hw_tls = 0;
}

static int
rack_pru_options(struct tcpcb *tp, int flags)
{
        if (flags & PRUS_OOB)
                return (EOPNOTSUPP);
        return (0);
}

static bool
rack_wake_check(struct tcpcb *tp)
{
        struct tcp_rack *rack;
        struct timeval tv;
        uint32_t cts;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->r_ctl.rc_hpts_flags) {
                cts = tcp_get_usecs(&tv);
                if ((rack->r_ctl.rc_hpts_flags & PACE_PKT_OUTPUT) == PACE_PKT_OUTPUT){
                        /*
                         * Pacing timer is up, check if we are ready.
                         */
                        if (TSTMP_GEQ(cts, rack->r_ctl.rc_last_output_to))
                                return (true);
                } else if ((rack->r_ctl.rc_hpts_flags & PACE_TMR_MASK) != 0) {
                        /*
                         * A timer is up, check if we are ready.
                         */
                        if (TSTMP_GEQ(cts, rack->r_ctl.rc_timer_exp))
                                return (true);
                }
        }
        return (false);
}

static struct tcp_function_block __tcp_rack = {
        .tfb_tcp_block_name = __XSTRING(STACKNAME),
        .tfb_tcp_output = rack_output,
        .tfb_do_queued_segments = ctf_do_queued_segments,
        .tfb_do_segment_nounlock = rack_do_segment_nounlock,
        .tfb_tcp_do_segment = rack_do_segment,
        .tfb_tcp_ctloutput = rack_ctloutput,
        .tfb_tcp_fb_init = rack_init,
        .tfb_tcp_fb_fini = rack_fini,
        .tfb_tcp_timer_stop_all = rack_stopall,
        .tfb_tcp_rexmit_tmr = rack_remxt_tmr,
        .tfb_tcp_handoff_ok = rack_handoff_ok,
        .tfb_tcp_mtu_chg = rack_mtu_change,
        .tfb_pru_options = rack_pru_options,
        .tfb_hwtls_change = rack_hw_tls_change,
        .tfb_chg_query = rack_chg_query,
        .tfb_switch_failed = rack_switch_failed,
        .tfb_early_wake_check = rack_wake_check,
        .tfb_compute_pipe = rack_compute_pipe,
        .tfb_stack_info = rack_stack_information,
        .tfb_inherit = rack_inherit,
        .tfb_flags = TCP_FUNC_OUTPUT_CANDROP | TCP_FUNC_DEFAULT_OK,

};

/*
 * rack_ctloutput() must drop the inpcb lock before performing copyin on
 * socket option arguments.  When it re-acquires the lock after the copy, it
 * has to revalidate that the connection is still valid for the socket
 * option.
 */
static int
rack_set_sockopt(struct tcpcb *tp, struct sockopt *sopt)
{
        struct inpcb *inp = tptoinpcb(tp);
#ifdef INET
        struct ip *ip;
#endif
        struct tcp_rack *rack;
        struct tcp_hybrid_req hybrid;
        uint64_t loptval;
        int32_t error = 0, optval;

        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack == NULL) {
                INP_WUNLOCK(inp);
                return (EINVAL);
        }
#ifdef INET
        ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr;
#endif

        switch (sopt->sopt_level) {
#ifdef INET6
        case IPPROTO_IPV6:
                MPASS(inp->inp_vflag & INP_IPV6PROTO);
                switch (sopt->sopt_name) {
                case IPV6_USE_MIN_MTU:
                        tcp6_use_min_mtu(tp);
                        break;
                }
                INP_WUNLOCK(inp);
                return (0);
#endif
#ifdef INET
        case IPPROTO_IP:
                switch (sopt->sopt_name) {
                case IP_TOS:
                        /*
                         * The DSCP codepoint has changed, update the fsb.
                         */
                        ip->ip_tos = rack->rc_inp->inp_ip_tos;
                        break;
                case IP_TTL:
                        /*
                         * The TTL has changed, update the fsb.
                         */
                        ip->ip_ttl = rack->rc_inp->inp_ip_ttl;
                        break;
                }
                INP_WUNLOCK(inp);
                return (0);
#endif
#ifdef SO_PEERPRIO
        case SOL_SOCKET:
                switch (sopt->sopt_name) {
                case SO_PEERPRIO:                       /*  SC-URL:bs */
                        /* Already read in and sanity checked in sosetopt(). */
                        if (inp->inp_socket) {
                                rack->client_bufferlvl = inp->inp_socket->so_peerprio;
                        }
                        break;
                }
                INP_WUNLOCK(inp);
                return (0);
#endif
        case IPPROTO_TCP:
                switch (sopt->sopt_name) {
                case TCP_RACK_TLP_REDUCE:               /*  URL:tlp_reduce */
                /*  Pacing related ones */
                case TCP_RACK_PACE_ALWAYS:              /*  URL:pace_always */
                case TCP_BBR_RACK_INIT_RATE:            /*  URL:irate */
                case TCP_RACK_PACE_MIN_SEG:             /*  URL:pace_min_seg */
                case TCP_RACK_PACE_MAX_SEG:             /*  URL:pace_max_seg */
                case TCP_RACK_FORCE_MSEG:               /*  URL:force_max_seg */
                case TCP_RACK_PACE_RATE_CA:             /*  URL:pr_ca */
                case TCP_RACK_PACE_RATE_SS:             /*  URL:pr_ss*/
                case TCP_RACK_PACE_RATE_REC:            /*  URL:pr_rec */
                case TCP_RACK_GP_INCREASE_CA:           /*  URL:gp_inc_ca */
                case TCP_RACK_GP_INCREASE_SS:           /*  URL:gp_inc_ss */
                case TCP_RACK_GP_INCREASE_REC:          /*  URL:gp_inc_rec */
                case TCP_RACK_RR_CONF:                  /*  URL:rrr_conf */
                case TCP_BBR_HDWR_PACE:                 /*  URL:hdwrpace */
                case TCP_HDWR_RATE_CAP:                 /*  URL:hdwrcap boolean */
                case TCP_PACING_RATE_CAP:               /*  URL:cap  -- used by side-channel */
                case TCP_HDWR_UP_ONLY:                  /*  URL:uponly -- hardware pacing  boolean */
                case TCP_FILLCW_RATE_CAP:               /*  URL:fillcw_cap */
                case TCP_RACK_PACING_BETA_ECN:          /*  URL:pacing_beta_ecn */
                case TCP_RACK_PACE_TO_FILL:             /*  URL:fillcw */
                        /* End pacing related */
                case TCP_DELACK:                        /*  URL:delack (in base TCP i.e. tcp_hints along with cc etc ) */
                case TCP_RACK_PRR_SENDALOT:             /*  URL:prr_sendalot */
                case TCP_RACK_MIN_TO:                   /*  URL:min_to */
                case TCP_RACK_EARLY_SEG:                /*  URL:early_seg */
                case TCP_RACK_REORD_THRESH:             /*  URL:reord_thresh */
                case TCP_RACK_REORD_FADE:               /*  URL:reord_fade */
                case TCP_RACK_TLP_THRESH:               /*  URL:tlp_thresh */
                case TCP_RACK_PKT_DELAY:                /*  URL:pkt_delay */
                case TCP_RACK_TLP_USE:                  /*  URL:tlp_use */
                case TCP_BBR_RACK_RTT_USE:              /*  URL:rttuse */
                case TCP_BBR_USE_RACK_RR:               /*  URL:rackrr */
                case TCP_NO_PRR:                        /*  URL:noprr */
                case TCP_TIMELY_DYN_ADJ:                /*  URL:dynamic */
                case TCP_DATA_AFTER_CLOSE:              /*  no URL */
                case TCP_RACK_NONRXT_CFG_RATE:          /*  URL:nonrxtcr */
                case TCP_SHARED_CWND_ENABLE:            /*  URL:scwnd */
                case TCP_RACK_MBUF_QUEUE:               /*  URL:mqueue */
                case TCP_RACK_NO_PUSH_AT_MAX:           /*  URL:npush */
                case TCP_SHARED_CWND_TIME_LIMIT:        /*  URL:lscwnd */
                case TCP_RACK_PROFILE:                  /*  URL:profile */
                case TCP_SIDECHAN_DIS:                  /*  URL:scodm */
                case TCP_HYBRID_PACING:                 /*  URL:pacing=hybrid */
                case TCP_USE_CMP_ACKS:                  /*  URL:cmpack */
                case TCP_RACK_ABC_VAL:                  /*  URL:labc */
                case TCP_REC_ABC_VAL:                   /*  URL:reclabc */
                case TCP_RACK_MEASURE_CNT:              /*  URL:measurecnt */
                case TCP_DEFER_OPTIONS:                 /*  URL:defer */
                case TCP_RACK_DSACK_OPT:                /*  URL:dsack */
                case TCP_RACK_TIMER_SLOP:               /*  URL:timer_slop */
                case TCP_RACK_ENABLE_HYSTART:           /*  URL:hystart */
                case TCP_RACK_SET_RXT_OPTIONS:          /*  URL:rxtsz */
                case TCP_RACK_HI_BETA:                  /*  URL:hibeta */
                case TCP_RACK_SPLIT_LIMIT:              /*  URL:split */
                case TCP_SS_EEXIT:                      /*  URL:eexit */
                case TCP_DGP_UPPER_BOUNDS:              /*  URL:upper */
                case TCP_RACK_PACING_DIVISOR:           /*  URL:divisor */
                case TCP_PACING_DND:                    /*  URL:dnd */
                case TCP_NO_TIMELY:                     /*  URL:notimely */
                case RACK_CSPR_IS_FCC:                  /*  URL:csprisfcc */
                case TCP_HONOR_HPTS_MIN:                /*  URL:hptsmin */
                case TCP_REC_IS_DYN:                    /*  URL:dynrec */
                case TCP_GP_USE_LTBW:                   /*  URL:useltbw */
                        goto process_opt;
                        break;
                default:
                        /* Filter off all unknown options to the base stack */
                        return (tcp_default_ctloutput(tp, sopt));
                        break;
                }
        default:
                INP_WUNLOCK(inp);
                return (0);
        }
process_opt:
        INP_WUNLOCK(inp);
        if ((sopt->sopt_name == TCP_PACING_RATE_CAP) ||
            (sopt->sopt_name == TCP_FILLCW_RATE_CAP)) {
                error = sooptcopyin(sopt, &loptval, sizeof(loptval), sizeof(loptval));
                /*
                 * We truncate it down to 32 bits for the socket-option trace this
                 * means rates > 34Gbps won't show right, but thats probably ok.
                 */
                optval = (uint32_t)loptval;
        } else if (sopt->sopt_name == TCP_HYBRID_PACING) {
                error = sooptcopyin(sopt, &hybrid, sizeof(hybrid), sizeof(hybrid));
        } else {
                error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval));
                /* Save it in 64 bit form too */
                loptval = optval;
        }
        if (error)
                return (error);
        INP_WLOCK(inp);
        if (tp->t_fb != &__tcp_rack) {
                INP_WUNLOCK(inp);
                return (ENOPROTOOPT);
        }
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack->defer_options && (rack->gp_ready == 0) &&
            (sopt->sopt_name != TCP_DEFER_OPTIONS) &&
            (sopt->sopt_name != TCP_HYBRID_PACING) &&
            (sopt->sopt_name != TCP_RACK_SET_RXT_OPTIONS) &&
            (sopt->sopt_name != TCP_RACK_PACING_BETA_ECN) &&
            (sopt->sopt_name != TCP_RACK_MEASURE_CNT)) {
                /* Options are being deferred */
                if (rack_add_deferred_option(rack, sopt->sopt_name, loptval)) {
                        INP_WUNLOCK(inp);
                        return (0);
                } else {
                        /* No memory to defer, fail */
                        INP_WUNLOCK(inp);
                        return (ENOMEM);
                }
        }
        error = rack_process_option(tp, rack, sopt->sopt_name, optval, loptval, &hybrid);
        INP_WUNLOCK(inp);
        return (error);
}

static void
rack_fill_info(struct tcpcb *tp, struct tcp_info *ti)
{

        INP_WLOCK_ASSERT(tptoinpcb(tp));
        bzero(ti, sizeof(*ti));

        ti->tcpi_state = tp->t_state;
        if ((tp->t_flags & TF_REQ_TSTMP) && (tp->t_flags & TF_RCVD_TSTMP))
                ti->tcpi_options |= TCPI_OPT_TIMESTAMPS;
        if (tp->t_flags & TF_SACK_PERMIT)
                ti->tcpi_options |= TCPI_OPT_SACK;
        if ((tp->t_flags & TF_REQ_SCALE) && (tp->t_flags & TF_RCVD_SCALE)) {
                ti->tcpi_options |= TCPI_OPT_WSCALE;
                ti->tcpi_snd_wscale = tp->snd_scale;
                ti->tcpi_rcv_wscale = tp->rcv_scale;
        }
        if (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT))
                ti->tcpi_options |= TCPI_OPT_ECN;
        if (tp->t_flags & TF_FASTOPEN)
                ti->tcpi_options |= TCPI_OPT_TFO;
        /* still kept in ticks is t_rcvtime */
        ti->tcpi_last_data_recv = ((uint32_t)ticks - tp->t_rcvtime) * tick;
        /* Since we hold everything in precise useconds this is easy */
        ti->tcpi_rtt = tp->t_srtt;
        ti->tcpi_rttvar = tp->t_rttvar;
        ti->tcpi_rto = tp->t_rxtcur;
        ti->tcpi_snd_ssthresh = tp->snd_ssthresh;
        ti->tcpi_snd_cwnd = tp->snd_cwnd;
        /*
         * FreeBSD-specific extension fields for tcp_info.
         */
        ti->tcpi_rcv_space = tp->rcv_wnd;
        ti->tcpi_rcv_nxt = tp->rcv_nxt;
        ti->tcpi_snd_wnd = tp->snd_wnd;
        ti->tcpi_snd_bwnd = 0;          /* Unused, kept for compat. */
        ti->tcpi_snd_nxt = tp->snd_nxt;
        ti->tcpi_snd_mss = tp->t_maxseg;
        ti->tcpi_rcv_mss = tp->t_maxseg;
        ti->tcpi_snd_rexmitpack = tp->t_sndrexmitpack;
        ti->tcpi_rcv_ooopack = tp->t_rcvoopack;
        ti->tcpi_snd_zerowin = tp->t_sndzerowin;
        ti->tcpi_total_tlp = tp->t_sndtlppack;
        ti->tcpi_total_tlp_bytes = tp->t_sndtlpbyte;
        ti->tcpi_rttmin = tp->t_rttlow;
#ifdef NETFLIX_STATS
        memcpy(&ti->tcpi_rxsyninfo, &tp->t_rxsyninfo, sizeof(struct tcpsyninfo));
#endif
#ifdef TCP_OFFLOAD
        if (tp->t_flags & TF_TOE) {
                ti->tcpi_options |= TCPI_OPT_TOE;
                tcp_offload_tcp_info(tp, ti);
        }
#endif
}

static int
rack_get_sockopt(struct tcpcb *tp, struct sockopt *sopt)
{
        struct inpcb *inp = tptoinpcb(tp);
        struct tcp_rack *rack;
        int32_t error, optval;
        uint64_t val, loptval;
        struct  tcp_info ti;
        /*
         * Because all our options are either boolean or an int, we can just
         * pull everything into optval and then unlock and copy. If we ever
         * add a option that is not a int, then this will have quite an
         * impact to this routine.
         */
        error = 0;
        rack = (struct tcp_rack *)tp->t_fb_ptr;
        if (rack == NULL) {
                INP_WUNLOCK(inp);
                return (EINVAL);
        }
        switch (sopt->sopt_name) {
        case TCP_INFO:
                /* First get the info filled */
                rack_fill_info(tp, &ti);
                /* Fix up the rtt related fields if needed */
                INP_WUNLOCK(inp);
                error = sooptcopyout(sopt, &ti, sizeof ti);
                return (error);
        /*
         * Beta is the congestion control value for NewReno that influences how
         * much of a backoff happens when loss is detected. It is normally set
         * to 50 for 50% i.e. the cwnd is reduced to 50% of its previous value
         * when you exit recovery.
         */
        case TCP_RACK_PACING_BETA:
                if (strcmp(tp->t_cc->name, CCALGONAME_NEWRENO) != 0)
                        error = EINVAL;
                else if (rack->rc_pacing_cc_set == 0)
                        optval = rack->r_ctl.rc_saved_beta;
                else {
                        /*
                         * Reach out into the CC data and report back what
                         * I have previously set. Yeah it looks hackish but
                         * we don't want to report the saved values.
                         */
                        if (tp->t_ccv.cc_data)
                                optval = ((struct newreno *)tp->t_ccv.cc_data)->beta;
                        else
                                error = EINVAL;
                }
                break;
        /*
         * Beta_ecn is the congestion control value for NewReno that influences how
         * much of a backoff happens when a ECN mark is detected. It is normally set
         * to 80 for 80% i.e. the cwnd is reduced by 20% of its previous value when
         * you exit recovery. Note that classic ECN has a beta of 50, it is only
         * ABE Ecn that uses this "less" value, but we do too with pacing :)
         */
        case TCP_RACK_PACING_BETA_ECN:
                if (strcmp(tp->t_cc->name, CCALGONAME_NEWRENO) != 0)
                        error = EINVAL;
                else if (rack->rc_pacing_cc_set == 0)
                        optval = rack->r_ctl.rc_saved_beta_ecn;
                else {
                        /*
                         * Reach out into the CC data and report back what
                         * I have previously set. Yeah it looks hackish but
                         * we don't want to report the saved values.
                         */
                        if (tp->t_ccv.cc_data)
                                optval = ((struct newreno *)tp->t_ccv.cc_data)->beta_ecn;
                        else
                                error = EINVAL;
                }
                break;
        case TCP_RACK_DSACK_OPT:
                optval = 0;
                if (rack->rc_rack_tmr_std_based) {
                        optval |= 1;
                }
                if (rack->rc_rack_use_dsack) {
                        optval |= 2;
                }
                break;
        case TCP_RACK_ENABLE_HYSTART:
        {
                if (tp->t_ccv.flags & CCF_HYSTART_ALLOWED) {
                        optval = RACK_HYSTART_ON;
                        if (tp->t_ccv.flags & CCF_HYSTART_CAN_SH_CWND)
                                optval = RACK_HYSTART_ON_W_SC;
                        if (tp->t_ccv.flags & CCF_HYSTART_CONS_SSTH)
                                optval = RACK_HYSTART_ON_W_SC_C;
                } else {
                        optval = RACK_HYSTART_OFF;
                }
        }
        break;
        case TCP_RACK_DGP_IN_REC:
                error = EINVAL;
                break;
        case TCP_RACK_HI_BETA:
                optval = rack->rack_hibeta;
                break;
        case TCP_DEFER_OPTIONS:
                optval = rack->defer_options;
                break;
        case TCP_RACK_MEASURE_CNT:
                optval = rack->r_ctl.req_measurements;
                break;
        case TCP_REC_ABC_VAL:
                optval = rack->r_use_labc_for_rec;
                break;
        case TCP_RACK_ABC_VAL:
                optval = rack->rc_labc;
                break;
        case TCP_HDWR_UP_ONLY:
                optval= rack->r_up_only;
                break;
        case TCP_FILLCW_RATE_CAP:
                loptval = rack->r_ctl.fillcw_cap;
                break;
        case TCP_PACING_RATE_CAP:
                loptval = rack->r_ctl.bw_rate_cap;
                break;
        case TCP_RACK_PROFILE:
                /* You cannot retrieve a profile, its write only */
                error = EINVAL;
                break;
        case TCP_SIDECHAN_DIS:
                optval = rack->r_ctl.side_chan_dis_mask;
                break;
        case TCP_HYBRID_PACING:
                /* You cannot retrieve hybrid pacing information, its write only */
                error = EINVAL;
                break;
        case TCP_USE_CMP_ACKS:
                optval = rack->r_use_cmp_ack;
                break;
        case TCP_RACK_PACE_TO_FILL:
                optval = rack->rc_pace_to_cwnd;
                break;
        case TCP_RACK_NO_PUSH_AT_MAX:
                optval = rack->r_ctl.rc_no_push_at_mrtt;
                break;
        case TCP_SHARED_CWND_ENABLE:
                optval = rack->rack_enable_scwnd;
                break;
        case TCP_RACK_NONRXT_CFG_RATE:
                optval = rack->rack_rec_nonrxt_use_cr;
                break;
        case TCP_NO_PRR:
                if (rack->rack_no_prr  == 1)
                        optval = 1;
                else if (rack->no_prr_addback == 1)
                        optval = 2;
                else
                        optval = 0;
                break;
        case TCP_GP_USE_LTBW:
                if (rack->dis_lt_bw) {
                        /* It is not used */
                        optval = 0;
                } else if (rack->use_lesser_lt_bw) {
                        /* we use min() */
                        optval = 1;
                } else {
                        /* we use max() */
                        optval = 2;
                }
                break;
        case TCP_RACK_DO_DETECTION:
                error = EINVAL;
                break;
        case TCP_RACK_MBUF_QUEUE:
                /* Now do we use the LRO mbuf-queue feature */
                optval = rack->r_mbuf_queue;
                break;
        case RACK_CSPR_IS_FCC:
                optval = rack->cspr_is_fcc;
                break;
        case TCP_TIMELY_DYN_ADJ:
                optval = rack->rc_gp_dyn_mul;
                break;
        case TCP_BBR_IWINTSO:
                error = EINVAL;
                break;
        case TCP_RACK_TLP_REDUCE:
                /* RACK TLP cwnd reduction (bool) */
                optval = rack->r_ctl.rc_tlp_cwnd_reduce;
                break;
        case TCP_BBR_RACK_INIT_RATE:
                val = rack->r_ctl.init_rate;
                /* convert to kbits per sec */
                val *= 8;
                val /= 1000;
                optval = (uint32_t)val;
                break;
        case TCP_RACK_FORCE_MSEG:
                optval = rack->rc_force_max_seg;
                break;
        case TCP_RACK_PACE_MIN_SEG:
                optval = rack->r_ctl.rc_user_set_min_segs;
                break;
        case TCP_RACK_PACE_MAX_SEG:
                /* Max segments in a pace */
                optval = rack->rc_user_set_max_segs;
                break;
        case TCP_RACK_PACE_ALWAYS:
                /* Use the always pace method */
                optval = rack->rc_always_pace;
                break;
        case TCP_RACK_PRR_SENDALOT:
                /* Allow PRR to send more than one seg */
                optval = rack->r_ctl.rc_prr_sendalot;
                break;
        case TCP_RACK_MIN_TO:
                /* Minimum time between rack t-o's in ms */
                optval = rack->r_ctl.rc_min_to;
                break;
        case TCP_RACK_SPLIT_LIMIT:
                optval = rack->r_ctl.rc_split_limit;
                break;
        case TCP_RACK_EARLY_SEG:
                /* If early recovery max segments */
                optval = rack->r_ctl.rc_early_recovery_segs;
                break;
        case TCP_RACK_REORD_THRESH:
                /* RACK reorder threshold (shift amount) */
                optval = rack->r_ctl.rc_reorder_shift;
                break;
        case TCP_SS_EEXIT:
                if (rack->r_ctl.gp_rnd_thresh) {
                        uint32_t v;

                        v = rack->r_ctl.gp_gain_req;
                        v <<= 17;
                        optval = v | (rack->r_ctl.gp_rnd_thresh & 0xff);
                        if (rack->r_ctl.gate_to_fs == 1)
                                optval |= 0x10000;
                } else
                        optval = 0;
                break;
        case TCP_RACK_REORD_FADE:
                /* Does reordering fade after ms time */
                optval = rack->r_ctl.rc_reorder_fade;
                break;
        case TCP_BBR_USE_RACK_RR:
                /* Do we use the rack cheat for rxt */
                optval = rack->use_rack_rr;
                break;
        case TCP_RACK_RR_CONF:
                optval = rack->r_rr_config;
                break;
        case TCP_HDWR_RATE_CAP:
                optval = rack->r_rack_hw_rate_caps;
                break;
        case TCP_BBR_HDWR_PACE:
                optval = rack->rack_hdw_pace_ena;
                break;
        case TCP_RACK_TLP_THRESH:
                /* RACK TLP theshold i.e. srtt+(srtt/N) */
                optval = rack->r_ctl.rc_tlp_threshold;
                break;
        case TCP_RACK_PKT_DELAY:
                /* RACK added ms i.e. rack-rtt + reord + N */
                optval = rack->r_ctl.rc_pkt_delay;
                break;
        case TCP_RACK_TLP_USE:
                optval = rack->rack_tlp_threshold_use;
                break;
        case TCP_PACING_DND:
                optval = rack->rc_pace_dnd;
                break;
        case TCP_RACK_PACE_RATE_CA:
                optval = rack->r_ctl.rc_fixed_pacing_rate_ca;
                break;
        case TCP_RACK_PACE_RATE_SS:
                optval = rack->r_ctl.rc_fixed_pacing_rate_ss;
                break;
        case TCP_RACK_PACE_RATE_REC:
                optval = rack->r_ctl.rc_fixed_pacing_rate_rec;
                break;
        case TCP_DGP_UPPER_BOUNDS:
                optval = rack->r_ctl.rack_per_upper_bound_ss;
                optval <<= 16;
                optval |= rack->r_ctl.rack_per_upper_bound_ca;
                break;
        case TCP_RACK_GP_INCREASE_SS:
                optval = rack->r_ctl.rack_per_of_gp_ca;
                break;
        case TCP_RACK_GP_INCREASE_CA:
                optval = rack->r_ctl.rack_per_of_gp_ss;
                break;
        case TCP_RACK_PACING_DIVISOR:
                optval = rack->r_ctl.pace_len_divisor;
                break;
        case TCP_BBR_RACK_RTT_USE:
                optval = rack->r_ctl.rc_rate_sample_method;
                break;
        case TCP_DELACK:
                optval = tp->t_delayed_ack;
                break;
        case TCP_DATA_AFTER_CLOSE:
                optval = rack->rc_allow_data_af_clo;
                break;
        case TCP_SHARED_CWND_TIME_LIMIT:
                optval = rack->r_limit_scw;
                break;
        case TCP_HONOR_HPTS_MIN:
                if (rack->r_use_hpts_min)
                        optval = rack->r_ctl.max_reduction;
                else
                        optval = 0;
                break;
        case TCP_REC_IS_DYN:
                optval = rack->rc_gp_no_rec_chg;
                break;
        case TCP_NO_TIMELY:
                optval = rack->rc_skip_timely;
                break;
        case TCP_RACK_TIMER_SLOP:
                optval = rack->r_ctl.timer_slop;
                break;
        default:
                return (tcp_default_ctloutput(tp, sopt));
                break;
        }
        INP_WUNLOCK(inp);
        if (error == 0) {
                if ((sopt->sopt_name == TCP_PACING_RATE_CAP) ||
                    (sopt->sopt_name == TCP_FILLCW_RATE_CAP))
                        error = sooptcopyout(sopt, &loptval, sizeof loptval);
                else
                        error = sooptcopyout(sopt, &optval, sizeof optval);
        }
        return (error);
}

static int
rack_ctloutput(struct tcpcb *tp, struct sockopt *sopt)
{
        if (sopt->sopt_dir == SOPT_SET) {
                return (rack_set_sockopt(tp, sopt));
        } else if (sopt->sopt_dir == SOPT_GET) {
                return (rack_get_sockopt(tp, sopt));
        } else {
                panic("%s: sopt_dir $%d", __func__, sopt->sopt_dir);
        }
}

static const char *rack_stack_names[] = {
        __XSTRING(STACKNAME),
#ifdef STACKALIAS
        __XSTRING(STACKALIAS),
#endif
};

static int
rack_ctor(void *mem, int32_t size, void *arg, int32_t how)
{
        memset(mem, 0, size);
        return (0);
}

static void
rack_dtor(void *mem, int32_t size, void *arg)
{

}

static bool rack_mod_inited = false;

static int
tcp_addrack(module_t mod, int32_t type, void *data)
{
        int32_t err = 0;
        int num_stacks;

        switch (type) {
        case MOD_LOAD:
                rack_zone = uma_zcreate(__XSTRING(MODNAME) "_map",
                    sizeof(struct rack_sendmap),
                    rack_ctor, rack_dtor, NULL, NULL, UMA_ALIGN_PTR, 0);

                rack_pcb_zone = uma_zcreate(__XSTRING(MODNAME) "_pcb",
                    sizeof(struct tcp_rack),
                    rack_ctor, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0);

                sysctl_ctx_init(&rack_sysctl_ctx);
                rack_sysctl_root = SYSCTL_ADD_NODE(&rack_sysctl_ctx,
                    SYSCTL_STATIC_CHILDREN(_net_inet_tcp),
                    OID_AUTO,
#ifdef STACKALIAS
                    __XSTRING(STACKALIAS),
#else
                    __XSTRING(STACKNAME),
#endif
                    CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
                    "");
                if (rack_sysctl_root == NULL) {
                        printf("Failed to add sysctl node\n");
                        err = EFAULT;
                        goto free_uma;
                }
                rack_init_sysctls();
                num_stacks = nitems(rack_stack_names);
                err = register_tcp_functions_as_names(&__tcp_rack, M_WAITOK,
                    rack_stack_names, &num_stacks);
                if (err) {
                        printf("Failed to register %s stack name for "
                            "%s module\n", rack_stack_names[num_stacks],
                            __XSTRING(MODNAME));
                        sysctl_ctx_free(&rack_sysctl_ctx);
free_uma:
                        uma_zdestroy(rack_zone);
                        uma_zdestroy(rack_pcb_zone);
                        rack_counter_destroy();
                        printf("Failed to register rack module -- err:%d\n", err);
                        return (err);
                }
                tcp_lro_reg_mbufq();
                rack_mod_inited = true;
                break;
        case MOD_QUIESCE:
                err = deregister_tcp_functions(&__tcp_rack, true, false);
                break;
        case MOD_UNLOAD:
                err = deregister_tcp_functions(&__tcp_rack, false, true);
                if (err == EBUSY)
                        break;
                if (rack_mod_inited) {
                        uma_zdestroy(rack_zone);
                        uma_zdestroy(rack_pcb_zone);
                        sysctl_ctx_free(&rack_sysctl_ctx);
                        rack_counter_destroy();
                        rack_mod_inited = false;
                }
                tcp_lro_dereg_mbufq();
                err = 0;
                break;
        default:
                return (EOPNOTSUPP);
        }
        return (err);
}

static moduledata_t tcp_rack = {
        .name = __XSTRING(MODNAME),
        .evhand = tcp_addrack,
        .priv = 0
};

MODULE_VERSION(MODNAME, 1);
DECLARE_MODULE(MODNAME, tcp_rack, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
MODULE_DEPEND(MODNAME, tcphpts, 1, 1, 1);

#endif /* #if !defined(INET) && !defined(INET6) */