diff options
-rw-r--r-- | sys/netinet/tcp_input.c | 71 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 82 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 1 |
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 * |