1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-10 06:47:55 -08:00

- fix three bugs pointed out in Stevens, i.a. updating timestamps correctly

- fix a 4.4bsd-lite2 bug, when tcp options are present the maximum segment
size is not updated correctly, so that fast recovery forces out a segment
which is split in two segments by tcp_output(), the fix is adpated from
FreeBSD, the effective mss is recorded after option negotiation in 3way
handshake.
[I was able to fix this on time spent at Center for Information Technology
Integration (citi.umich.edu)]
This commit is contained in:
provos 1998-10-28 21:34:32 +00:00
parent e74bf56f77
commit 5f0eddb4ad
4 changed files with 77 additions and 53 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tcp_input.c,v 1.19 1998/06/27 02:42:40 deraadt Exp $ */ /* $OpenBSD: tcp_input.c,v 1.20 1998/10/28 21:34:32 provos Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/* /*
@ -641,9 +641,9 @@ findpcb:
/* /*
* If last ACK falls within this segment's sequence numbers, * If last ACK falls within this segment's sequence numbers,
* record the timestamp. * record the timestamp.
* Fix from Braden, see Stevens p. 870
*/ */
if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) {
SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) {
tp->ts_recent_age = tcp_now; tp->ts_recent_age = tcp_now;
tp->ts_recent = ts_val; tp->ts_recent = ts_val;
} }
@ -980,7 +980,8 @@ trimthenstep6:
tiflags &= ~TH_URG; tiflags &= ~TH_URG;
todrop--; todrop--;
} }
if (todrop >= ti->ti_len) { if (todrop >= ti->ti_len ||
(todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
/* /*
* Any valid FIN must be to the left of the * Any valid FIN must be to the left of the
* window. At this point, FIN must be a * window. At this point, FIN must be a
@ -1064,10 +1065,10 @@ trimthenstep6:
/* /*
* If last ACK falls within this segment's sequence numbers, * If last ACK falls within this segment's sequence numbers,
* record its timestamp. * record its timestamp.
* Fix from Braden, see Stevens p. 870
*/ */
if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && if (ts_present && TSTMP_GEQ(ts_val, tp->ts_recent) &&
SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) {
((tiflags & (TH_SYN|TH_FIN)) != 0))) {
tp->ts_recent_age = tcp_now; tp->ts_recent_age = tcp_now;
tp->ts_recent = ts_val; tp->ts_recent = ts_val;
} }
@ -1579,7 +1580,7 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
int *ts_present; int *ts_present;
u_int32_t *ts_val, *ts_ecr; u_int32_t *ts_val, *ts_ecr;
{ {
u_int16_t mss; u_int16_t mss = 0;
int opt, optlen; int opt, optlen;
for (; cnt > 0; cnt -= optlen, cp += optlen) { for (; cnt > 0; cnt -= optlen, cp += optlen) {
@ -1605,7 +1606,6 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
continue; continue;
bcopy((char *) cp + 2, (char *) &mss, sizeof(mss)); bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
NTOHS(mss); NTOHS(mss);
(void) tcp_mss(tp, mss); /* sets t_maxseg */
break; break;
case TCPOPT_WINDOW: case TCPOPT_WINDOW:
@ -1638,6 +1638,9 @@ tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr)
break; break;
} }
} }
/* Update t_maxopd and t_maxseg after all options are processed */
if (ti->ti_flags & TH_SYN)
(void) tcp_mss(tp, mss); /* sets t_maxseg */
} }
/* /*
@ -1762,6 +1765,12 @@ tcp_xmit_timer(tp, rtt)
* window to be a single segment if the destination isn't local. * window to be a single segment if the destination isn't local.
* While looking at the routing entry, we also initialize other path-dependent * While looking at the routing entry, we also initialize other path-dependent
* parameters from pre-set or cached values in the routing entry. * parameters from pre-set or cached values in the routing entry.
*
* Also take into account the space needed for options that we
* send regularly. Make maxseg shorter by that amount to assure
* 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.
*/ */
int int
tcp_mss(tp, offer) tcp_mss(tp, offer)
@ -1788,9 +1797,11 @@ tcp_mss(tp, offer)
satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr; satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
rtalloc(ro); rtalloc(ro);
} }
if ((rt = ro->ro_rt) == (struct rtentry *)0) if ((rt = ro->ro_rt) == (struct rtentry *)0) {
tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
return (tcp_mssdflt); return (tcp_mssdflt);
} }
}
ifp = rt->rt_ifp; ifp = rt->rt_ifp;
so = inp->inp_socket; so = inp->inp_socket;
@ -1828,13 +1839,6 @@ tcp_mss(tp, offer)
#endif /* RTV_MTU */ #endif /* RTV_MTU */
{ {
mss = ifp->if_mtu - sizeof(struct tcpiphdr); 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)) if (!in_localaddr(inp->inp_faddr))
mss = min(mss, tcp_mssdflt); mss = min(mss, tcp_mssdflt);
} }
@ -1848,8 +1852,27 @@ tcp_mss(tp, offer)
*/ */
if (offer) if (offer)
mss = min(mss, offer); mss = min(mss, offer);
mss = max(mss, 32); /* sanity */ mss = max(mss, 64); /* sanity - at least max opt. space */
if (mss < tp->t_maxseg || offer != 0) { /*
* 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
* from maxseg, because now every segment carries options
* and thus we normally have somewhat less data in segments.
*/
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 there's a pipesize, change the socket buffer * If there's a pipesize, change the socket buffer
* to that size. Make the socket buffers an integral * to that size. Make the socket buffers an integral
@ -1880,7 +1903,6 @@ tcp_mss(tp, offer)
bufsize = sb_max; bufsize = sb_max;
(void)sbreserve(&so->so_rcv, bufsize); (void)sbreserve(&so->so_rcv, bufsize);
} }
}
tp->snd_cwnd = mss; tp->snd_cwnd = mss;
#ifdef RTV_SSTHRESH #ifdef RTV_SSTHRESH

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tcp_output.c,v 1.10 1998/05/18 21:11:06 provos Exp $ */ /* $OpenBSD: tcp_output.c,v 1.11 1998/10/28 21:34:33 provos Exp $ */
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */ /* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
/* /*
@ -194,7 +194,7 @@ again:
goto send; goto send;
if (tp->t_force) if (tp->t_force)
goto send; goto send;
if (len >= tp->max_sndwnd / 2) if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
goto send; goto send;
if (SEQ_LT(tp->snd_nxt, tp->snd_max)) if (SEQ_LT(tp->snd_nxt, tp->snd_max))
goto send; goto send;
@ -330,10 +330,10 @@ send:
/* /*
* Adjust data length if insertion of options will * Adjust data length if insertion of options will
* bump the packet length beyond the t_maxseg length. * bump the packet length beyond the t_maxopd length.
*/ */
if (len > tp->t_maxseg - optlen) { if (len > tp->t_maxopd - optlen) {
len = tp->t_maxseg - optlen; len = tp->t_maxopd - optlen;
sendalot = 1; sendalot = 1;
flags &= ~TH_FIN; flags &= ~TH_FIN;
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tcp_subr.c,v 1.10 1998/05/18 21:11:07 provos Exp $ */ /* $OpenBSD: tcp_subr.c,v 1.11 1998/10/28 21:34:33 provos Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */ /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/* /*
@ -235,7 +235,7 @@ tcp_newtcpcb(inp)
return ((struct tcpcb *)0); return ((struct tcpcb *)0);
bzero((char *) tp, sizeof(struct tcpcb)); bzero((char *) tp, sizeof(struct tcpcb));
LIST_INIT(&tp->segq); LIST_INIT(&tp->segq);
tp->t_maxseg = tcp_mssdflt; tp->t_maxseg = tp->t_maxopd = tcp_mssdflt;
tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
tp->t_inpcb = inp; tp->t_inpcb = inp;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tcp_var.h,v 1.11 1998/06/10 03:40:05 beck Exp $ */ /* $OpenBSD: tcp_var.h,v 1.12 1998/10/28 21:34:33 provos Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */ /* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/* /*
@ -98,6 +98,8 @@ struct tcpcb {
* for slow start exponential to * for slow start exponential to
* linear switch * linear switch
*/ */
u_int t_maxopd; /* mss plus options */
/* /*
* transmit timing stuff. See below for scale of srtt and rttvar. * transmit timing stuff. See below for scale of srtt and rttvar.
* "Variance" is actually smoothed difference. * "Variance" is actually smoothed difference.