summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2000-09-20 17:00:24 +0000
committerNiels Provos <provos@cvs.openbsd.org>2000-09-20 17:00:24 +0000
commit4b8370dd1c4bd6e2767ecbe164cb73e8ae337404 (patch)
tree4b79bf6fdbe32d96b777b51831c18364cb9b2c3e /sys/netinet
parentdc087a71e34204c41f6ef06c16a54e74c6ea00be (diff)
correctly calculate mss
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_input.c210
-rw-r--r--sys/netinet/tcp_output.c8
-rw-r--r--sys/netinet/tcp_subr.c17
-rw-r--r--sys/netinet/tcp_var.h3
4 files changed, 123 insertions, 115 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 */
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 8b6ad202982..f1ab4a5ab05 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_output.c,v 1.32 2000/09/18 22:06:38 provos Exp $ */
+/* $OpenBSD: tcp_output.c,v 1.33 2000/09/20 17:00:22 provos Exp $ */
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
/*
@@ -512,9 +512,13 @@ send:
opt[0] = TCPOPT_MAXSEG;
opt[1] = 4;
- mss = htons((u_int16_t) tcp_mss(tp, 0));
+ mss = htons((u_int16_t) tcp_mss(tp, flags & TH_ACK ?
+ tp->t_maxopd : 0));
bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss));
optlen = 4;
+
+ if (flags & TH_ACK)
+ tcp_mss_update(tp);
#ifdef TCP_SACK
/*
* If this is the first SYN of connection (not a SYN
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 6cc41c276a7..c9fa20fb9d6 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_subr.c,v 1.31 2000/09/18 22:06:38 provos Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.32 2000/09/20 17:00:23 provos Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
@@ -427,8 +427,9 @@ tcp_newtcpcb(inp)
return ((struct tcpcb *)0);
bzero((char *) tp, sizeof(struct tcpcb));
LIST_INIT(&tp->segq);
- tp->t_maxseg = tp->t_maxopd = tcp_mssdflt;
-
+ tp->t_maxseg = tcp_mssdflt;
+ tp->t_maxopd = 0;
+
#ifdef TCP_SACK
tp->sack_disable = tcp_do_sack ? 0 : 1;
#endif
@@ -864,17 +865,9 @@ tcp_mtudisc(inp, errno)
return;
}
- /*
- * Slow start out of the error condition. We
- * use the MTU because we know it's smaller
- * than the previously transmitted segment.
- *
- * Note: This is more conservative than the
- * suggestion in RFC 2414
- */
if (rt->rt_rmx.rmx_mtu != 0) {
+ /* also takes care of congestion window */
tcp_mss(tp, -1);
- tp->snd_cwnd = rt->rt_rmx.rmx_mtu;
}
}
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index e4c25532abd..39c03b853d2 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_var.h,v 1.30 2000/09/18 22:06:38 provos Exp $ */
+/* $OpenBSD: tcp_var.h,v 1.31 2000/09/20 17:00:23 provos Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@@ -343,6 +343,7 @@ int tcp6_input __P((struct mbuf **, int *, int));
#endif
void tcp_input __P((struct mbuf *, ...));
int tcp_mss __P((struct tcpcb *, int));
+void tcp_mss_update __P((struct tcpcb *));
void tcp_mtudisc __P((struct inpcb *, int));
struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));