+ tcp_mssdflt);
+ }
+ /*
+ * 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 INET6
+ mss = (isipv6 ? tcp_maxmtu6(rt) : tcp_maxmtu(rt));
+#else
+ mss = tcp_maxmtu(rt);
+#endif
+ lck_mtx_unlock(rt_mtx);
+ 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;
+ tp->t_unacksegs = 0;
+ (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.
+ */
+ if (tp->snd_cwnd > th->th_ack - tp->snd_una)
+ tp->snd_cwnd -= th->th_ack - tp->snd_una;
+ else
+ tp->snd_cwnd = 0;
+ tp->snd_cwnd += 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
+tcp_dropdropablreq(struct socket *head)
+{
+ struct socket *so, *sonext;
+ 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;
+
+ if ((head->so_options & SO_ACCEPTCONN) == 0)
+ return 0;
+
+ so = TAILQ_FIRST(&head->so_incomp);
+ if (!so)
+ return 0;
+
+ microtime(&tv);
+ if ((i = (tv.tv_sec - old_runtime.tv_sec)) != 0) {
+ old_runtime = tv;
+ old_cnt = cur_cnt / i;
+ cur_cnt = 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 (or being served) */
+ while (so) {
+ inp = (struct inpcb *)so->so_pcb;
+
+ sonext = TAILQ_NEXT(so, so_list);
+
+ if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) != WNT_STOPUSING) {
+ /* Avoid the issue of a socket being accepted by one input thread
+ * and being dropped by another input thread.
+ * If we can't get a hold on this mutex, then grab the next socket in line.
+ */
+ if (lck_mtx_try_lock(inp->inpcb_mtx)) {
+ so->so_usecount++;
+ if ((so->so_usecount == 2) && so->so_state & SS_INCOMP)
+ break;
+ else {/* don't use if beeing accepted or used in any other way */
+ in_pcb_checkstate(inp, WNT_RELEASE, 1);
+ tcp_unlock(so, 1, 0);
+ }
+ }
+ }
+ so = sonext;
+
+ }
+ if (!so)
+ return 0;
+
+ TAILQ_REMOVE(&head->so_incomp, so, so_list);
+ tcp_unlock(head, 0, 0);
+
+ /* Makes sure socket is still in the right state to be discarded */
+
+ if (in_pcb_checkstate(inp, WNT_RELEASE, 1) == WNT_STOPUSING) {
+ tcp_unlock(so, 1, 0);
+ tcp_lock(head, 0, 0);
+ return 0;
+ }
+
+ if (so->so_usecount != 2 || !(so->so_state & SS_INCOMP)) {
+ /* do not discard: that socket is beeing accepted */
+ tcp_unlock(so, 1, 0);
+ tcp_lock(head, 0, 0);
+ return 0;
+ }
+
+ so->so_head = NULL;
+
+ /*
+ * We do not want to lose track of the PCB right away in case we receive
+ * more segments from the peer
+ */
+ tp = sototcpcb(so);
+ so->so_flags |= SOF_OVERFLOW;
+ tp->t_state = TCPS_TIME_WAIT;
+ (void) tcp_close(tp);
+ tp->t_unacksegs = 0;
+ tcpstat.tcps_drops++;
+ tcp_canceltimers(tp);
+ add_to_time_wait(tp);
+
+ tcp_unlock(so, 1, 0);
+ tcp_lock(head, 0, 0);
+ head->so_incqlen--;
+ head->so_qlen--;
+ return 1;
+}
+
+static int
+tcp_getstat SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+
+ int error;