From 4ed600dbd011260d672618e4bba7bd1b95b06b5d Mon Sep 17 00:00:00 2001 From: thorpej Date: Mon, 22 Sep 1997 21:49:55 +0000 Subject: [PATCH] Fix several annoyances related to MSS handling in BSD TCP: - Don't overload t_maxseg. Previous behavior was to set it to the min of the peer's advertised MSS, our advertised MSS, and tcp_mssdflt (for non-local networks). This breaks PMTU discovery running on either host. Instead, remember the MSS we advertise, and use it as appropriate (in silly window avoidance). - Per last bullet, split tcp_mss() into several functions for handling MSS (ours and peer's), and performing various tasks when a connection becomes ESTABLISHED. - Introduce a new function, tcp_segsize(), which computes the max size for every segment transmitted in tcp_output(). This will eventually be used to hook in PMTU discovery. --- sys/netinet/tcp_input.c | 183 ++++----------------------------------- sys/netinet/tcp_output.c | 58 ++++++++++--- sys/netinet/tcp_subr.c | 177 ++++++++++++++++++++++++++++++++++++- sys/netinet/tcp_var.h | 15 +++- 4 files changed, 249 insertions(+), 184 deletions(-) diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index dd52498c0b23..b2b7c12600f1 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_input.c,v 1.31 1997/07/28 22:07:38 thorpej Exp $ */ +/* $NetBSD: tcp_input.c,v 1.32 1997/09/22 21:49:55 thorpej Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 @@ -651,12 +651,12 @@ after_listen: tp->irs = ti->ti_seq; tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; - tcp_mss(tp, opti.maxseg); + tcp_mss_from_peer(tp, opti.maxseg); + tcp_rmx_rtt(tp); if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { tcpstat.tcps_connects++; soisconnected(so); - tp->t_state = TCPS_ESTABLISHED; - tp->t_timer[TCPT_KEEP] = tcp_keepidle; + tcp_established(tp); /* Do window scaling on this connection? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -918,8 +918,7 @@ after_listen: goto dropwithreset; tcpstat.tcps_connects++; soisconnected(so); - tp->t_state = TCPS_ESTABLISHED; - tp->t_timer[TCPT_KEEP] = tcp_keepidle; + tcp_established(tp); /* Do window scaling? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1391,7 +1390,7 @@ tcp_dooptions(tp, cp, cnt, ti, oi) case TCPOPT_TIMESTAMP: if (optlen != TCPOLEN_TIMESTAMP) continue; - oi -> ts_present = 1; + oi->ts_present = 1; bcopy(cp + 2, &oi->ts_val, sizeof(oi->ts_val)); NTOHL(oi->ts_val); bcopy(cp + 6, &oi->ts_ecr, sizeof(oi->ts_ecr)); @@ -1519,155 +1518,6 @@ tcp_xmit_timer(tp, rtt) tp->t_softerror = 0; } -/* - * Determine a reasonable value for maxseg size. - * If the route is known, check route for mtu. - * If none, use an mss that can be handled on the outgoing - * interface without forcing IP to fragment; if bigger than - * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES - * to utilize large mbufs. If no route is found, route has no mtu, - * or the destination isn't local, use a default, hopefully conservative - * size (usually 512 or the default IP max size, but no more than the mtu - * of the interface), as we can't discover anything about intervening - * gateways or networks. 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. - */ -int -tcp_mss(tp, offer) - register struct tcpcb *tp; - u_int offer; -{ - struct route *ro; - register struct rtentry *rt; - struct ifnet *ifp; - register int rtt, mss; - u_long bufsize; - struct inpcb *inp; - struct socket *so; - - inp = tp->t_inpcb; - ro = &inp->inp_route; - - if ((rt = ro->ro_rt) == (struct rtentry *)0) { - /* No route yet, so try to acquire one */ - if (!in_nullhost(inp->inp_faddr)) { - 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); - } - if ((rt = ro->ro_rt) == (struct rtentry *)0) - return (tcp_mssdflt); - } - ifp = rt->rt_ifp; - so = inp->inp_socket; - -#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) - tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ); - tp->t_srtt = rtt / - ((RTM_RTTUNIT / PR_SLOWHZ) >> (TCP_RTT_SHIFT + 2)); - if (rt->rt_rmx.rmx_rttvar) - tp->t_rttvar = rt->rt_rmx.rmx_rttvar / - ((RTM_RTTUNIT / PR_SLOWHZ) >> (TCP_RTTVAR_SHIFT + 2)); - else - /* default variation is +- 1 rtt */ - tp->t_rttvar = - tp->t_srtt >> (TCP_RTT_SHIFT - TCP_RTTVAR_SHIFT); - TCPT_RANGESET(tp->t_rxtcur, - ((tp->t_srtt >> 2) + tp->t_rttvar) >> (1 + 2), - tp->t_rttmin, TCPTV_REXMTMAX); - } - /* - * if there's an mtu associated with the route, use it - */ - if (rt->rt_rmx.rmx_mtu) - mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); - else -#endif /* RTV_MTU */ - { - mss = ifp->if_mtu - sizeof(struct tcpiphdr); -#if (MCLBYTES & (MCLBYTES - 1)) == 0 - if (mss > MCLBYTES) - mss &= ~(MCLBYTES-1); -#else - if (mss > MCLBYTES) - mss = mss / MCLBYTES * MCLBYTES; -#endif - if (!in_localaddr(inp->inp_faddr)) - mss = min(mss, tcp_mssdflt); - } - /* - * 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) - mss = min(mss, offer); - mss = max(mss, 32); /* sanity */ - if (mss < tp->t_maxseg || offer != 0) { - /* - * If there's a pipesize, change the socket buffer - * to that size. Make the socket buffers an integral - * number of mss units; if the mss is larger than - * the socket buffer, decrease the mss. - */ -#ifdef RTV_SPIPE - if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0) -#endif - bufsize = so->so_snd.sb_hiwat; - if (bufsize < mss) - mss = bufsize; - 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) -#endif - bufsize = so->so_rcv.sb_hiwat; - if (bufsize > mss) { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - (void)sbreserve(&so->so_rcv, bufsize); - } - } - tp->snd_cwnd = mss; - -#ifdef RTV_SSTHRESH - if (rt->rt_rmx.rmx_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. - */ - tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh); - } -#endif /* RTV_MTU */ - return (mss); -} - /* * TCP compressed state engine. Currently used to hold compressed * state for SYN_RECEIVED. @@ -2021,7 +1871,10 @@ syn_cache_get(so, m) tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tcpstat.tcps_accepts++; - tcp_mss(tp, sc->sc_peermaxseg); + /* Initialize tp->t_ourmss before we deal with the peer's! */ + tp->t_ourmss = sc->sc_ourmaxseg; + tcp_mss_from_peer(tp, sc->sc_peermaxseg); + tcp_rmx_rtt(tp); tp->snd_wl1 = sc->sc_irs; tp->rcv_up = sc->sc_irs + 1; @@ -2116,6 +1969,8 @@ syn_cache_unreach(ip, th) * this to the syn cache, and send back a segment: * * to the source. + * + * XXX We don't properly handle SYN-with-data! */ int @@ -2127,12 +1982,13 @@ syn_cache_add(so, m, optp, optlen, oi) struct tcp_opt_info *oi; { register struct tcpiphdr *ti; - struct tcpcb tb; + struct tcpcb tb, *tp; long win; struct syn_cache *sc, **sc_prev; struct syn_cache_head *scp; extern int tcp_do_rfc1323; + tp = sototcpcb(so); ti = mtod(m, struct tcpiphdr *); /* @@ -2185,6 +2041,7 @@ syn_cache_add(so, m, optp, optlen, oi) sc->sc_iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; sc->sc_peermaxseg = oi->maxseg; + sc->sc_ourmaxseg = tcp_mss_to_advertise(tp); sc->sc_tstmp = (tcp_do_rfc1323 && (tb.t_flags & TF_RCVD_TSTMP)) ? 1 : 0; if ((tb.t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -2219,12 +2076,6 @@ syn_cache_respond(sc, m, ti, win, ts) { u_int8_t *optp; int optlen; - u_int16_t mss; - extern unsigned long in_maxmtu; - - mss = in_maxmtu - sizeof(struct tcpiphdr); - if (!in_localaddr(ti->ti_dst)) - mss = min(mss, tcp_mssdflt); /* * Tack on the TCP options. If there isn't enough trailing @@ -2252,8 +2103,8 @@ syn_cache_respond(sc, m, ti, win, ts) optp = (u_int8_t *)(ti + 1); optp[0] = TCPOPT_MAXSEG; optp[1] = 4; - optp[2] = (mss >> 8) & 0xff; - optp[3] = mss & 0xff; + optp[2] = (sc->sc_ourmaxseg >> 8) & 0xff; + optp[3] = sc->sc_ourmaxseg & 0xff; optlen = 4; if (sc->sc_request_r_scale != 15) { diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 673e88df20d9..1e7cc7839142 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */ +/* $NetBSD: tcp_output.c,v 1.17 1997/09/22 21:49:59 thorpej Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -72,6 +73,34 @@ extern struct mbuf *m_copypack(); #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ +static __inline int tcp_segsize __P((struct tcpcb *)); +static __inline int +tcp_segsize(tp) + struct tcpcb *tp; +{ + struct inpcb *inp = tp->t_inpcb; + struct rtentry *rt; + struct ifnet *ifp; + int size; + + if ((rt = in_pcbrtentry(inp)) == NULL) { + size = tcp_mssdflt; + goto out; + } + + ifp = rt->rt_ifp; + + if (rt->rt_rmx.rmx_mtu) + size = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); + else if (in_localaddr(inp->inp_faddr) || ifp->if_flags & IFF_LOOPBACK) + size = ifp->if_mtu - sizeof(struct tcpiphdr); + else + size = tcp_mssdflt; + + out: + return (min(tp->t_maxseg, size)); +} + /* * Tcp output routine: figure out what should be sent and send it. */ @@ -86,7 +115,9 @@ tcp_output(tp) register struct tcpiphdr *ti; u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; - int idle, sendalot; + int idle, sendalot, segsize; + + segsize = tcp_segsize(tp); /* * Determine length of data that should be transmitted, @@ -164,8 +195,8 @@ again: tp->snd_nxt = tp->snd_una; } } - if (len > tp->t_maxseg) { - len = tp->t_maxseg; + if (len > segsize) { + len = segsize; flags &= ~TH_FIN; sendalot = 1; } @@ -183,7 +214,7 @@ again: * to send into a small window), then must resend. */ if (len) { - if (len == tp->t_maxseg) + if (len == segsize) goto send; if ((idle || tp->t_flags & TF_NODELAY) && len + off >= so->so_snd.sb_cc) @@ -212,7 +243,7 @@ again: long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - (tp->rcv_adv - tp->rcv_nxt); - if (adv >= (long) (2 * tp->t_maxseg)) + if (adv >= (long) (2 * tp->t_ourmss)) goto send; if (2 * adv >= (long) so->so_rcv.sb_hiwat) goto send; @@ -282,13 +313,12 @@ send: hdrlen = sizeof (struct tcpiphdr); if (flags & TH_SYN) { tp->snd_nxt = tp->iss; + tp->t_ourmss = tcp_mss_to_advertise(tp); if ((tp->t_flags & TF_NOOPT) == 0) { - u_int16_t mss; - opt[0] = TCPOPT_MAXSEG; opt[1] = 4; - mss = htons((u_int16_t) tcp_mss(tp, 0)); - bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss)); + opt[2] = (tp->t_ourmss >> 8) & 0xff; + opt[3] = tp->t_ourmss & 0xff; optlen = 4; if ((tp->t_flags & TF_REQ_SCALE) && @@ -326,10 +356,10 @@ send: /* * Adjust data length if insertion of options will - * bump the packet length beyond the t_maxseg length. + * bump the packet length beyond the segsize length. */ - if (len > tp->t_maxseg - optlen) { - len = tp->t_maxseg - optlen; + if (len > segsize - optlen) { + len = segsize - optlen; flags &= ~TH_FIN; sendalot = 1; } @@ -450,7 +480,7 @@ send: * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. */ - if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg) + if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_ourmss) win = 0; if (win > (long)TCP_MAXWIN << tp->rcv_scale) win = (long)TCP_MAXWIN << tp->rcv_scale; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 0ee00eb6eed2..e1b6ed610a9f 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_subr.c,v 1.27 1997/07/23 21:26:51 thorpej Exp $ */ +/* $NetBSD: tcp_subr.c,v 1.28 1997/09/22 21:50:02 thorpej Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 @@ -221,6 +221,7 @@ tcp_newtcpcb(inp) bzero((caddr_t)tp, sizeof(struct tcpcb)); LIST_INIT(&tp->segq); tp->t_maxseg = tcp_mssdflt; + tp->t_ourmss = tcp_mssdflt; tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; tp->t_inpcb = inp; @@ -457,3 +458,177 @@ tcp_quench(inp, errno) if (tp) tp->snd_cwnd = tp->t_maxseg; } + +/* + * Compute the MSS to advertise to the peer. Called only during + * the 3-way handshake. If we are the server (peer initiated + * connection), we are called with the TCPCB for the listen + * socket. If we are the client (we initiated connection), we + * are called witht he TCPCB for the actual connection. + */ +int +tcp_mss_to_advertise(tp) + const struct tcpcb *tp; +{ + extern u_long in_maxmtu; + struct inpcb *inp; + struct socket *so; + int mss; + + inp = tp->t_inpcb; + so = inp->inp_socket; + + /* + * In order to avoid defeating path MTU discovery on the peer, + * we advertise the max MTU of all attached networks as our MSS, + * per RFC 1191, section 3.1. + * + * XXX Should we allow room for the timestamp option if + * XXX rfc1323 is enabled? + */ + mss = in_maxmtu - sizeof(struct tcpiphdr); + + return (mss); +} + +/* + * Set connection variables based on the peer's advertised 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: Our advertised MSS value must be initialized in the TCPCB + * before this routine is called! + */ +void +tcp_mss_from_peer(tp, offer) + struct tcpcb *tp; + int offer; +{ + struct inpcb *inp = tp->t_inpcb; + struct socket *so = inp->inp_socket; +#if defined(RTV_SPIPE) || defined(RTV_SSTHRESH) + struct rtentry *rt = in_pcbrtentry(inp); +#endif + u_long bufsize; + int mss; + + /* + * Assume our MSS is the MSS of the peer, unless they sent us + * an offer. Do not accept offers less than 32 bytes. + */ + mss = tp->t_ourmss; + if (offer) + mss = offer; + mss = max(mss, 32); /* sanity */ + + /* + * If there's a pipesize, change the socket buffer to that size. + * Make the socket buffer an integral number of MSS units. If + * the MSS is larger than the socket buffer, artificially decrease + * the MSS. + */ +#ifdef RTV_SPIPE + if (rt != NULL && rt->rt_rmx.rmx_sendpipe != 0) + bufsize = rt->rt_rmx.rmx_sendpipe; + else +#endif + bufsize = so->so_snd.sb_hiwat; + if (bufsize < mss) + mss = bufsize; + else { + bufsize = roundup(bufsize, mss); + if (bufsize > sb_max) + bufsize = sb_max; + (void) sbreserve(&so->so_snd, bufsize); + } + tp->t_maxseg = mss; + + /* Initialize the initial congestion window. */ + tp->snd_cwnd = mss; + +#ifdef RTV_SSTHRESH + if (rt != NULL && rt->rt_rmx.rmx_ssthresh) { + /* + * There's some sort of gateway or interface buffer + * limit on the path. Use this to set the slow + * start threshold, but set the threshold to no less + * than 2 * MSS. + */ + tp->snd_ssthresh = max(2 * mss, rt->rt_rmx.rmx_ssthresh); + } +#endif +} + +/* + * Processing necessary when a TCP connection is established. + */ +void +tcp_established(tp) + struct tcpcb *tp; +{ + struct inpcb *inp = tp->t_inpcb; + struct socket *so = inp->inp_socket; +#ifdef RTV_RPIPE + struct rtentry *rt = in_pcbrtentry(inp); +#endif + u_long bufsize; + + tp->t_state = TCPS_ESTABLISHED; + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + +#ifdef RTV_RPIPE + if (rt != NULL && rt->rt_rmx.rmx_recvpipe != 0) + bufsize = rt->rt_rmx.rmx_recvpipe; + else +#endif + bufsize = so->so_rcv.sb_hiwat; + if (bufsize > tp->t_ourmss) { + bufsize = roundup(bufsize, tp->t_ourmss); + if (bufsize > sb_max) + bufsize = sb_max; + (void) sbreserve(&so->so_rcv, bufsize); + } +} + +/* + * Check if there's an initial rtt or rttvar. Convert from the + * route-table units to scaled multiples of the slow timeout timer. + * Called only during the 3-way handshake. + */ +void +tcp_rmx_rtt(tp) + struct tcpcb *tp; +{ +#ifdef RTV_RTT + struct rtentry *rt; + int rtt; + + if ((rt = in_pcbrtentry(tp->t_inpcb)) == NULL) + return; + + 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) + tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ); + tp->t_srtt = rtt / + ((RTM_RTTUNIT / PR_SLOWHZ) >> (TCP_RTT_SHIFT + 2)); + if (rt->rt_rmx.rmx_rttvar) { + tp->t_rttvar = rt->rt_rmx.rmx_rttvar / + ((RTM_RTTUNIT / PR_SLOWHZ) >> + (TCP_RTTVAR_SHIFT + 2)); + } else { + /* Default variation is +- 1 rtt */ + tp->t_rttvar = + tp->t_srtt >> (TCP_RTT_SHIFT - TCP_RTTVAR_SHIFT); + } + TCPT_RANGESET(tp->t_rxtcur, + ((tp->t_srtt >> 2) + tp->t_rttvar) >> (1 + 2), + tp->t_rttmin, TCPTV_REXMTMAX); + } +#endif +} diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 971e5d1fc873..4eae3625d845 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_var.h,v 1.22 1997/08/29 16:02:43 gwr Exp $ */ +/* $NetBSD: tcp_var.h,v 1.23 1997/09/22 21:50:04 thorpej Exp $ */ /* * Copyright (c) 1982, 1986, 1993, 1994 @@ -49,7 +49,8 @@ struct tcpcb { short t_rxtshift; /* log(2) of rexmt exp. backoff */ short t_rxtcur; /* current retransmit value */ short t_dupacks; /* consecutive dup acks recd */ - u_short t_maxseg; /* maximum segment size */ + u_short t_maxseg; /* peer's maximum segment size */ + u_short t_ourmss; /* our's maximum segment size */ char t_force; /* 1 if forcing out a byte */ u_short t_flags; #define TF_ACKNOW 0x0001 /* ack peer immediately */ @@ -143,6 +144,10 @@ struct tcp_opt_info { * This structure should not exceed 32 bytes. * XXX On the Alpha, it's already 36-bytes, which rounds to 40. * XXX Need to eliminate the pointer. + * + * XXX We've blown 32 bytes on non-Alpha systems, too, since we're + * XXX storing the maxseg we advertised to the peer. Should we + * XXX create another malloc bucket? Should we care? */ struct syn_cache { struct syn_cache *sc_next; @@ -155,6 +160,7 @@ struct syn_cache { u_int16_t sc_sport; u_int16_t sc_dport; u_int16_t sc_peermaxseg; + u_int16_t sc_ourmaxseg; u_int8_t sc_timer; u_int8_t sc_request_r_scale : 4, sc_requested_s_scale : 4; @@ -328,10 +334,12 @@ struct tcpcb * void tcp_dooptions __P((struct tcpcb *, u_char *, int, struct tcpiphdr *, struct tcp_opt_info *)); void tcp_drain __P((void)); +void tcp_established __P((struct tcpcb *)); void tcp_fasttimo __P((void)); void tcp_init __P((void)); void tcp_input __P((struct mbuf *, ...)); -int tcp_mss __P((struct tcpcb *, u_int)); +int tcp_mss_to_advertise __P((const struct tcpcb *)); +void tcp_mss_from_peer __P((struct tcpcb *, int)); struct tcpcb * tcp_newtcpcb __P((struct inpcb *)); void tcp_notify __P((struct inpcb *, int)); @@ -342,6 +350,7 @@ void tcp_quench __P((struct inpcb *, int)); int tcp_reass __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *)); int tcp_respond __P((struct tcpcb *, struct tcpiphdr *, struct mbuf *, tcp_seq, tcp_seq, int)); +void tcp_rmx_rtt __P((struct tcpcb *)); void tcp_setpersist __P((struct tcpcb *)); void tcp_slowtimo __P((void)); struct tcpiphdr *