+/*
+ * Determine a reasonable value for maxseg size.
+ * If the route is known, check route for mtu.
+ * We also initialize the congestion/slow start
+ * window to be a single segment if the destination isn't local.
+ * While looking at the routing entry, we also initialize other path-dependent
+ * parameters from pre-set or cached values in the routing entry.
+ */
+void
+tp_mss(tpcb, nhdr_size)
+ register struct tp_pcb *tpcb;
+ int nhdr_size;
+{
+ register struct rtentry *rt;
+ struct ifnet *ifp;
+ register int rtt, mss;
+ u_long bufsize;
+ int i, ssthresh = 0, rt_mss;
+ struct socket *so;
+
+ if (tpcb->tp_ptpdusize)
+ mss = tpcb->tp_ptpdusize << 7;
+ else
+ mss = 1 << tpcb->tp_tpdusize;
+ so = tpcb->tp_sock;
+ if ((rt = *(tpcb->tp_routep)) == 0) {
+ bufsize = so->so_rcv.sb_hiwat;
+ goto punt_route;
+ }
+ ifp = rt->rt_ifp;
+
+#ifdef RTV_MTU /* if route characteristics exist ... */
+ /*
+ * While we're here, check if there's an initial rtt
+ * or rttvar. Convert from the route-table units
+ * to hz ticks for the smoothed timers and slow-timeout units
+ * for other inital variables.
+ */
+ if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
+ tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT;
+ if (rt->rt_rmx.rmx_rttvar)
+ tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar
+ * hz / RTM_RTTUNIT;
+ else
+ tpcb->tp_rtv = tpcb->tp_rtt;
+ }
+ /*
+ * if there's an mtu associated with the route, use it
+ */
+ if (rt->rt_rmx.rmx_mtu)
+ rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size;
+ else
+#endif /* RTV_MTU */
+ rt_mss = (ifp->if_mtu - nhdr_size);
+ if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */
+ mss > rt_mss /* network won't support what was asked for */)
+ mss = rt_mss;
+ /* can propose mtu which are multiples of 128 */
+ mss &= ~0x7f;
+ /*
+ * If there's a pipesize, change the socket buffer
+ * to that size.
+ */
+#ifdef RTV_SPIPE
+ if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) {
+#endif
+ bufsize = min(bufsize, so->so_snd.sb_hiwat);
+ (void) sbreserve(&so->so_snd, bufsize);
+ }
+#ifdef RTV_SPIPE
+ if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) {
+#endif
+ bufsize = min(bufsize, so->so_rcv.sb_hiwat);
+ (void) sbreserve(&so->so_rcv, bufsize);
+ } else
+ bufsize = so->so_rcv.sb_hiwat;
+#ifdef RTV_SSTHRESH
+ /*
+ * There's some sort of gateway or interface
+ * buffer limit on the path. Use this to set
+ * the slow start threshhold, but set the
+ * threshold to no less than 2*mss.
+ */
+ ssthresh = rt->rt_rmx.rmx_ssthresh;
+punt_route:
+ /*
+ * The current mss is initialized to the default value.
+ * If we compute a smaller value, reduce the current mss.
+ * If we compute a larger value, return it for use in sending
+ * a max seg size option.
+ * If we received an offer, don't exceed it.
+ * However, do not accept offers under 128 bytes.
+ */
+ if (tpcb->tp_l_tpdusize)
+ mss = min(mss, tpcb->tp_l_tpdusize);
+ /*
+ * We want a minimum recv window of 4 packets to
+ * signal packet loss by duplicate acks.
+ */
+ mss = min(mss, bufsize >> 2) & ~0x7f;
+ mss = max(mss, 128); /* sanity */
+ tpcb->tp_cong_win =
+ (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize;
+ tpcb->tp_l_tpdusize = mss;
+ tp_rsyset(tpcb);
+ tpcb->tp_ssthresh = max(2 * mss, ssthresh);
+ /* Calculate log2 of mss */
+ for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++)
+ if ((1 << i) > mss)
+ break;
+ i--;
+ tpcb->tp_tpdusize = i;
+#endif /* RTV_MTU */
+}