+ /*
+ * Slower link window correction:
+ * If a value is specificied for slowlink_wsize use it for PPP links
+ * believed to be on a serial modem (speed <128Kbps). Excludes 9600bps as
+ * it is the default value adversized by pseudo-devices over ppp.
+ */
+ if (rt->rt_ifp->if_type == IFT_PPP && slowlink_wsize > 0 &&
+ rt->rt_ifp->if_baudrate > 9600 && rt->rt_ifp->if_baudrate <= 128000) {
+ tp->t_flags |= TF_SLOWLINK;
+ }
+
+ if (rt->rt_rmx.rmx_mtu)
+ mss = rt->rt_rmx.rmx_mtu;
+ else {
+ mss =
+#if INET6
+ (isipv6 ? nd_ifinfo[rt->rt_ifp->if_index].linkmtu :
+#endif
+ rt->rt_ifp->if_mtu
+#if INET6
+ );
+#endif
+ }
+ return (mss - min_protoh);
+}
+
+/*
+ * On a partial ack arrives, force the retransmission of the
+ * next unacknowledged segment. Do not clear tp->t_dupacks.
+ * By setting snd_nxt to ti_ack, this forces retransmission timer to
+ * be started again.
+ */
+static void
+tcp_newreno_partial_ack(tp, th)
+ struct tcpcb *tp;
+ struct tcphdr *th;
+{
+ tcp_seq onxt = tp->snd_nxt;
+ u_long ocwnd = tp->snd_cwnd;
+ tp->t_timer[TCPT_REXMT] = 0;
+ tp->t_rtttime = 0;
+ tp->snd_nxt = th->th_ack;
+ /*
+ * Set snd_cwnd to one segment beyond acknowledged offset
+ * (tp->snd_una has not yet been updated when this function
+ * is called)
+ */
+ tp->snd_cwnd = tp->t_maxseg + (th->th_ack - tp->snd_una);
+ tp->t_flags |= TF_ACKNOW;
+ (void) tcp_output(tp);
+ tp->snd_cwnd = ocwnd;
+ if (SEQ_GT(onxt, tp->snd_nxt))
+ tp->snd_nxt = onxt;
+ /*
+ * Partial window deflation. Relies on fact that tp->snd_una
+ * not updated yet.
+ */
+ tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg);
+}
+
+/*
+ * Drop a random TCP connection that hasn't been serviced yet and
+ * is eligible for discard. There is a one in qlen chance that
+ * we will return a null, saying that there are no dropable
+ * requests. In this case, the protocol specific code should drop
+ * the new request. This insures fairness.
+ *
+ * The listening TCP socket "head" must be locked
+ */
+static int
+tcpdropdropablreq(struct socket *head)
+{
+ struct socket *so;
+ unsigned int i, j, qlen;
+ static int rnd;
+ static struct timeval old_runtime;
+ static unsigned int cur_cnt, old_cnt;
+ struct timeval tv;
+ struct inpcb *inp = NULL;
+ struct tcpcb *tp;
+
+ microtime(&tv);
+ if ((i = (tv.tv_sec - old_runtime.tv_sec)) != 0) {
+ old_runtime = tv;
+ old_cnt = cur_cnt / i;
+ cur_cnt = 0;
+ }
+
+ so = TAILQ_FIRST(&head->so_incomp);
+ if (!so)
+ return 0;
+
+ qlen = head->so_incqlen;
+ if (++cur_cnt > qlen || old_cnt > qlen) {
+ rnd = (314159 * rnd + 66329) & 0xffff;
+ j = ((qlen + 1) * rnd) >> 16;
+
+ while (j-- && so)
+ so = TAILQ_NEXT(so, so_list);
+ }
+ /* Find a connection that is not already closing */
+ while (so) {
+ inp = (struct inpcb *)so->so_pcb;
+
+ if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) != WNT_STOPUSING)
+ break;
+
+ so = TAILQ_NEXT(so, so_list);
+ }
+ if (!so)
+ return 0;
+
+ head->so_incqlen--;
+ head->so_qlen--;
+ TAILQ_REMOVE(&head->so_incomp, so, so_list);
+ tcp_unlock(head, 0, 0);
+
+ /* Let's remove this connection from the incomplete list */
+ tcp_lock(so, 1, 0);
+
+ if (in_pcb_checkstate(inp, WNT_RELEASE, 1) == WNT_STOPUSING) {
+ tcp_unlock(so, 1, 0);
+ return 0;
+ }
+
+ so->so_head = NULL;
+ so->so_usecount--; /* No more held by so_head */
+
+ /*
+ * We do not want to lose track of the PCB right away in case we receive
+ * more segments from the peer
+ */
+ tp = sototcpcb(so);
+ tp->t_flags |= TF_LQ_OVERFLOW;
+ tp->t_state = TCPS_CLOSED;
+ (void) tcp_output(tp);
+ tcpstat.tcps_drops++;
+ soisdisconnected(so);
+ tcp_canceltimers(tp);
+ add_to_time_wait(tp);
+
+ tcp_unlock(so, 1, 0);
+ tcp_lock(head, 0, 0);
+
+ return 1;
+
+}
+
+static int
+tcp_getstat SYSCTL_HANDLER_ARGS
+{
+
+ int error;
+
+ if (req->oldptr == 0) {
+ req->oldlen= (size_t)sizeof(struct tcpstat);
+ }