summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_input.c
diff options
context:
space:
mode:
authorprovos <provos@openbsd.org>2000-09-20 17:00:22 +0000
committerprovos <provos@openbsd.org>2000-09-20 17:00:22 +0000
commit39b94094a22f24a827039933d795fcc2bc0bbe6c (patch)
tree81c642a2bc3841878b7fbc215117272e1717e9d6 /sys/netinet/tcp_input.c
parentfix in_pcbrtentry (diff)
downloadwireguard-openbsd-39b94094a22f24a827039933d795fcc2bc0bbe6c.tar.xz
wireguard-openbsd-39b94094a22f24a827039933d795fcc2bc0bbe6c.zip
correctly calculate mss
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r--sys/netinet/tcp_input.c210
1 files changed, 110 insertions, 100 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index dda3213bbb9..493d778d08a 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.73 2000/09/19 18:10:59 deraadt Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.74 2000/09/20 17:00:22 provos Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -1764,7 +1764,7 @@ trimthenstep6:
#if defined (TCP_SACK)
if (tp->t_dupacks < tcprexmtthresh)
#endif
- tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
+ tp->snd_cwnd = ulmin(cw + incr, TCP_MAXWIN<<tp->snd_scale);
}
ND6_HINT(tp);
if (acked > so->so_snd.sb_cc) {
@@ -2220,8 +2220,12 @@ tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr)
}
}
/* Update t_maxopd and t_maxseg after all options are processed */
- if (th->th_flags & TH_SYN)
+ if (th->th_flags & TH_SYN) {
(void) tcp_mss(tp, mss); /* sets t_maxseg */
+
+ if (mss)
+ tcp_mss_update(tp);
+ }
}
#if defined(TCP_SACK)
@@ -2769,69 +2773,35 @@ tcp_xmit_timer(tp, rtt)
* that we can send maxseg amount of data even when the options
* are present. Store the upper limit of the length of options plus
* data in maxopd.
+ *
+ * NOTE: offer == -1 indicates that the maxseg size changed due to
+ * Path MTU discovery.
*/
int
tcp_mss(tp, offer)
register struct tcpcb *tp;
int offer;
{
- struct route *ro;
- register struct rtentry *rt;
+ struct rtentry *rt;
struct ifnet *ifp;
- register int rtt, mss, mssopt;
- u_long bufsize;
+ int mss, mssopt;
int iphlen;
#ifdef INET6
int is_ipv6 = 0;
#endif
struct inpcb *inp;
- struct socket *so;
inp = tp->t_inpcb;
- ro = &inp->inp_route;
- so = inp->inp_socket;
-
- if ((rt = ro->ro_rt) == (struct rtentry *)0) {
- /* No route yet, so try to acquire one */
-#ifdef INET6
- bzero(ro, sizeof(struct route_in6));
-#else
- bzero(ro, sizeof(struct route));
-#endif
- /*
- * Get a new IPv6 route if an IPv6 destination, otherwise, get
- * and IPv4 route (including those pesky IPv4-mapped addresses).
- */
- switch (sotopf(so)) {
-#ifdef INET6
- case AF_INET6:
- if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
- break;
- ro->ro_dst.sa_family = AF_INET6;
- ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
- ((struct sockaddr_in6 *) &ro->ro_dst)->sin6_addr =
- inp->inp_faddr6;
- rtalloc(ro);
- break;
-#endif /* INET6 */
- case AF_INET:
- if (inp->inp_faddr.s_addr == INADDR_ANY)
- break;
- ro->ro_dst.sa_family = AF_INET;
- ro->ro_dst.sa_len = sizeof(ro->ro_dst);
- satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
- rtalloc(ro);
- break;
- }
- if ((rt = ro->ro_rt) == (struct rtentry *)0) {
- tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
- return (tcp_mssdflt);
- }
- }
- ifp = rt->rt_ifp;
mssopt = mss = tcp_mssdflt;
+ rt = in_pcbrtentry(inp);
+
+ if (rt == NULL)
+ goto out;
+
+ ifp = rt->rt_ifp;
+
switch (tp->pf) {
#ifdef INET6
case AF_INET6:
@@ -2847,34 +2817,7 @@ tcp_mss(tp, offer)
goto out;
}
-#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 scaled multiples of the slow timeout timer.
- */
- if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
- /*
- * XXX the lock bit for MTU indicates that the value
- * is also a minimum value; this is subject to time.
- */
- if (rt->rt_rmx.rmx_locks & RTV_RTT)
- TCPT_RANGESET(tp->t_rttmin,
- rtt / (RTM_RTTUNIT / PR_SLOWHZ),
- TCPTV_MIN, TCPTV_REXMTMAX);
- tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
- if (rt->rt_rmx.rmx_rttvar)
- tp->t_rttvar = rt->rt_rmx.rmx_rttvar /
- (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
- else
- /* default variation is +- 1 rtt */
- tp->t_rttvar =
- tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
- TCPT_RANGESET((long) tp->t_rxtcur,
- ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
- tp->t_rttmin, TCPTV_REXMTMAX);
- }
-
+#ifdef RTV_MTU
/*
* if there's an mtu associated with the route and we support
* path MTU discovery for the underlying protocol family, use it.
@@ -2921,17 +2864,6 @@ tcp_mss(tp, offer)
out:
/*
- * The current mss, t_maxseg, 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, but don't store it for use
- * unless we received an offer at least that large from peer.
- * However, do not accept offers under 32 bytes.
- */
- if (offer && offer != -1)
- mss = min(mss, offer);
- mss = max(mss, 64); /* sanity - at least max opt. space */
- /*
* maxopd stores the maximum length of data AND options
* in a segment; maxseg is the amount of data in a normal
* segment. We need to store this value (maxopd) apart
@@ -2944,13 +2876,93 @@ tcp_mss(tp, offer)
(tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)
mss -= TCPOLEN_TSTAMP_APPA;
-#if (MCLBYTES & (MCLBYTES - 1)) == 0
- if (mss > MCLBYTES)
- mss &= ~(MCLBYTES-1);
-#else
- if (mss > MCLBYTES)
- mss = mss / MCLBYTES * MCLBYTES;
+ /*
+ * The current mss, t_maxseg, 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, but don't store it for use
+ * unless we received an offer at least that large from peer.
+ * However, do not accept offers under 32 bytes.
+ */
+ if (offer && offer != -1)
+ mss = min(mss, offer);
+ mss = max(mss, 64); /* sanity - at least max opt. space */
+
+ if (offer == -1) {
+ /* mss changed due to Path MTU discovery */
+ if (mss < tp->t_maxseg) {
+ /*
+ * Follow suggestion in RFC 2414 to reduce the
+ * congestion window by the ratio of the old
+ * segment size to the new segment size.
+ */
+ tp->snd_cwnd = ulmax((tp->snd_cwnd / tp->t_maxseg) *
+ mss, mss);
+ }
+ } else
+ tp->snd_cwnd = mss;
+
+ tp->t_maxseg = mss;
+
+ return (offer != -1 ? mssopt : mss);
+}
+
+/*
+ * Set connection variables based on the effective MSS.
+ * We are passed the TCPCB for the actual connection. If we
+ * are the server, we are called by the compressed state engine
+ * when the 3-way handshake is complete. If we are the client,
+ * we are called when we recieve the SYN,ACK from the server.
+ *
+ * NOTE: The t_maxseg value must be initialized in the TCPCB
+ * before this routine is called!
+ */
+void
+tcp_mss_update(tp)
+ struct tcpcb *tp;
+{
+ int mss, rtt;
+ u_long bufsize;
+ struct rtentry *rt;
+ struct socket *so;
+
+ so = tp->t_inpcb->inp_socket;
+ mss = tp->t_maxseg;
+
+ rt = in_pcbrtentry(tp->t_inpcb);
+
+ if (rt == NULL)
+ return;
+
+#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 scaled multiples of the slow timeout timer.
+ */
+ if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
+ /*
+ * XXX the lock bit for MTU indicates that the value
+ * is also a minimum value; this is subject to time.
+ */
+ if (rt->rt_rmx.rmx_locks & RTV_RTT)
+ TCPT_RANGESET(tp->t_rttmin,
+ rtt / (RTM_RTTUNIT / PR_SLOWHZ),
+ TCPTV_MIN, TCPTV_REXMTMAX);
+ tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
+ if (rt->rt_rmx.rmx_rttvar)
+ tp->t_rttvar = rt->rt_rmx.rmx_rttvar /
+ (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
+ else
+ /* default variation is +- 1 rtt */
+ tp->t_rttvar =
+ tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
+ TCPT_RANGESET((long) tp->t_rxtcur,
+ ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
+ tp->t_rttmin, TCPTV_REXMTMAX);
+ }
#endif
+
/*
* If there's a pipesize, change the socket buffer
* to that size. Make the socket buffers an integral
@@ -2961,15 +2973,16 @@ tcp_mss(tp, offer)
if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0)
#endif
bufsize = so->so_snd.sb_hiwat;
- if (bufsize < mss)
+ if (bufsize < mss) {
mss = bufsize;
- else {
+ /* Update t_maxseg and t_maxopd */
+ tcp_mss(tp, mss);
+ } else {
bufsize = roundup(bufsize, mss);
if (bufsize > sb_max)
bufsize = sb_max;
(void)sbreserve(&so->so_snd, bufsize);
}
- tp->t_maxseg = mss;
#ifdef RTV_RPIPE
if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)
@@ -2985,7 +2998,6 @@ tcp_mss(tp, offer)
tcp_rscale(tp, so->so_rcv.sb_hiwat);
#endif
}
- tp->snd_cwnd = mss;
#ifdef RTV_SSTHRESH
if (rt->rt_rmx.rmx_ssthresh) {
@@ -2998,8 +3010,6 @@ tcp_mss(tp, offer)
tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh);
}
#endif /* RTV_MTU */
-
- return (offer != -1 ? mssopt : mss);
}
#endif /* TUBA_INCLUDE */