aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/tcp_input.c71
-rw-r--r--sys/netinet/tcp_subr.c82
-rw-r--r--sys/netinet/tcp_var.h1
3 files changed, 66 insertions, 88 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index f8ae94e9ed55..e96ef443a5db 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -2790,13 +2790,11 @@ tcp_xmit_timer(struct tcpcb *tp, int rtt)
* segment. Outgoing SYN/ACK MSS settings are handled in tcp_mssopt().
*/
void
-tcp_mss(struct tcpcb *tp, int offer)
+tcp_mss_update(struct tcpcb *tp, int offer, struct hc_metrics_lite *metricptr)
{
- int rtt, mss;
- u_long bufsize;
+ int mss;
u_long maxmtu;
struct inpcb *inp = tp->t_inpcb;
- struct socket *so;
struct hc_metrics_lite metrics;
int origoffer = offer;
int mtuflags = 0;
@@ -2829,6 +2827,10 @@ tcp_mss(struct tcpcb *tp, int offer)
if (maxmtu == 0)
return;
+ /* Check the interface for TSO capabilities. */
+ if (mtuflags & CSUM_TSO)
+ tp->t_flags |= TF_TSO;
+
/* What have we got? */
switch (offer) {
case 0:
@@ -2852,19 +2854,14 @@ tcp_mss(struct tcpcb *tp, int offer)
* to at least minmss.
*/
offer = max(offer, V_tcp_minmss);
- /*
- * Sanity check: make sure that maxopd will be large
- * enough to allow some data on segments even if the
- * all the option space is used (40bytes). Otherwise
- * funny things may happen in tcp_output.
- */
- offer = max(offer, 64);
}
/*
* rmx information is now retrieved from tcp_hostcache.
*/
tcp_hc_get(&inp->inp_inc, &metrics);
+ if (metricptr != NULL)
+ bcopy(&metrics, metricptr, sizeof(struct hc_metrics_lite));
/*
* If there's a discovered mtu int tcp hostcache, use it
@@ -2887,10 +2884,36 @@ tcp_mss(struct tcpcb *tp, int offer)
!in_localaddr(inp->inp_faddr))
mss = min(mss, V_tcp_mssdflt);
}
+ /*
+ * XXX - The above conditional (mss = maxmtu - min_protoh)
+ * probably violates the TCP spec.
+ * The problem is that, since we don't know the
+ * other end's MSS, we are supposed to use a conservative
+ * default. But, if we do that, then MTU discovery will
+ * never actually take place, because the conservative
+ * default is much less than the MTUs typically seen
+ * on the Internet today. For the moment, we'll sweep
+ * this under the carpet.
+ *
+ * The conservative default might not actually be a problem
+ * if the only case this occurs is when sending an initial
+ * SYN with options and data to a host we've never talked
+ * to before. Then, they will reply with an MSS value which
+ * will get recorded and the new parameters should get
+ * recomputed. For Further Study.
+ */
}
mss = min(mss, offer);
/*
+ * Sanity check: make sure that maxopd will be large
+ * enough to allow some data on segments even if the
+ * all the option space is used (40bytes). Otherwise
+ * funny things may happen in tcp_output.
+ */
+ mss = max(mss, 64);
+
+ /*
* 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
@@ -2916,6 +2939,28 @@ tcp_mss(struct tcpcb *tp, int offer)
mss = mss / MCLBYTES * MCLBYTES;
#endif
tp->t_maxseg = mss;
+}
+
+void
+tcp_mss(struct tcpcb *tp, int offer)
+{
+ int rtt, mss;
+ u_long bufsize;
+ struct inpcb *inp;
+ struct socket *so;
+ struct hc_metrics_lite metrics;
+#ifdef INET6
+ int isipv6;
+#endif
+ KASSERT(tp != NULL, ("%s: tp == NULL", __func__));
+
+ tcp_mss_update(tp, offer, &metrics);
+
+ mss = tp->t_maxseg;
+ inp = tp->t_inpcb;
+#ifdef INET6
+ isipv6 = ((inp->inp_vflag & INP_IPV6) != 0) ? 1 : 0;
+#endif
/*
* If there's a pipesize, change the socket buffer to that size,
@@ -3022,10 +3067,6 @@ tcp_mss(struct tcpcb *tp, int offer)
tp->snd_cwnd = mss * V_ss_fltsz_local;
else
tp->snd_cwnd = mss * V_ss_fltsz;
-
- /* Check the interface for TSO capabilities. */
- if (mtuflags & CSUM_TSO)
- tp->t_flags |= TF_TSO;
}
/*
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 3a979b0a9aff..1d24991b3543 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1514,13 +1514,7 @@ struct inpcb *
tcp_mtudisc(struct inpcb *inp, int errno)
{
struct tcpcb *tp;
- struct socket *so = inp->inp_socket;
- u_int maxmtu;
- u_int romtu;
- int mss;
-#ifdef INET6
- int isipv6;
-#endif /* INET6 */
+ struct socket *so;
INP_WLOCK_ASSERT(inp);
if ((inp->inp_vflag & INP_TIMEWAIT) ||
@@ -1530,72 +1524,14 @@ tcp_mtudisc(struct inpcb *inp, int errno)
tp = intotcpcb(inp);
KASSERT(tp != NULL, ("tcp_mtudisc: tp == NULL"));
-#ifdef INET6
- isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0;
-#endif
- maxmtu = tcp_hc_getmtu(&inp->inp_inc); /* IPv4 and IPv6 */
- romtu =
-#ifdef INET6
- isipv6 ? tcp_maxmtu6(&inp->inp_inc, NULL) :
-#endif /* INET6 */
- tcp_maxmtu(&inp->inp_inc, NULL);
- if (!maxmtu)
- maxmtu = romtu;
- else
- maxmtu = min(maxmtu, romtu);
- if (!maxmtu) {
- tp->t_maxopd = tp->t_maxseg =
-#ifdef INET6
- isipv6 ? V_tcp_v6mssdflt :
-#endif /* INET6 */
- V_tcp_mssdflt;
- return (inp);
- }
- mss = maxmtu -
-#ifdef INET6
- (isipv6 ? sizeof(struct ip6_hdr) + sizeof(struct tcphdr) :
-#endif /* INET6 */
- sizeof(struct tcpiphdr)
-#ifdef INET6
- )
-#endif /* INET6 */
- ;
-
- /*
- * XXX - The above conditional probably violates the TCP
- * spec. The problem is that, since we don't know the
- * other end's MSS, we are supposed to use a conservative
- * default. But, if we do that, then MTU discovery will
- * never actually take place, because the conservative
- * default is much less than the MTUs typically seen
- * on the Internet today. For the moment, we'll sweep
- * this under the carpet.
- *
- * The conservative default might not actually be a problem
- * if the only case this occurs is when sending an initial
- * SYN with options and data to a host we've never talked
- * to before. Then, they will reply with an MSS value which
- * will get recorded and the new parameters should get
- * recomputed. For Further Study.
- */
- if (tp->t_maxopd <= mss)
- return (inp);
- tp->t_maxopd = mss;
-
- if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
- (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;
-#endif
- if (so->so_snd.sb_hiwat < mss)
- mss = so->so_snd.sb_hiwat;
-
- tp->t_maxseg = mss;
+ tcp_mss_update(tp, -1, NULL);
+
+ so = inp->inp_socket;
+ SOCKBUF_LOCK(&so->so_snd);
+ /* If the mss is larger than the socket buffer, decrease the mss. */
+ if (so->so_snd.sb_hiwat < tp->t_maxseg)
+ tp->t_maxseg = so->so_snd.sb_hiwat;
+ SOCKBUF_UNLOCK(&so->so_snd);
V_tcpstat.tcps_mturesent++;
tp->t_rtttime = 0;
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 9d656addd2f3..44257df2b819 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -546,6 +546,7 @@ void tcp_reass_init(void);
void tcp_input(struct mbuf *, int);
u_long tcp_maxmtu(struct in_conninfo *, int *);
u_long tcp_maxmtu6(struct in_conninfo *, int *);
+void tcp_mss_update(struct tcpcb *, int, struct hc_metrics_lite *);
void tcp_mss(struct tcpcb *, int);
int tcp_mssopt(struct in_conninfo *);
struct inpcb *