aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/tcp_output.c
diff options
context:
space:
mode:
authorGarrett Wollman <wollman@FreeBSD.org>1995-02-09 23:13:27 +0000
committerGarrett Wollman <wollman@FreeBSD.org>1995-02-09 23:13:27 +0000
commita0292f237572bd29b1bd4b376a2198c6f404e349 (patch)
tree6b8f4500f8844dcde0c5fcc625cf24bb530f5240 /sys/netinet/tcp_output.c
parentfd65acba73782643f21738462dfd0acfa60d41ad (diff)
downloadsrc-a0292f237572bd29b1bd4b376a2198c6f404e349.tar.gz
src-a0292f237572bd29b1bd4b376a2198c6f404e349.zip
Merge Transaction TCP, courtesy of Andras Olah <olah@cs.utwente.nl> and
Bob Braden <braden@isi.edu>. NB: This has not had David's TCP ACK hack re-integrated. It is not clear what the correct solution to this problem is, if any. If a better solution doesn't pop up in response to this message, I'll put David's code back in (or he's welcome to do so himself).
Notes
Notes: svn path=/head/; revision=6283
Diffstat (limited to 'sys/netinet/tcp_output.c')
-rw-r--r--sys/netinet/tcp_output.c160
1 files changed, 145 insertions, 15 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 161baedf1465..3af7caa7a660 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_output.c 8.3 (Berkeley) 12/30/93
- * $Id: tcp_output.c,v 1.5 1995/01/24 08:03:22 davidg Exp $
+ * $Id: tcp_output.c,v 1.6 1995/01/26 03:56:20 davidg Exp $
*/
#include <sys/param.h>
@@ -66,8 +66,6 @@ extern struct mbuf *m_copypack();
#endif
-#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */
-
/*
* Tcp output routine: figure out what should be sent and send it.
*/
@@ -80,9 +78,13 @@ tcp_output(tp)
int off, flags, error;
register struct mbuf *m;
register struct tcpiphdr *ti;
- u_char opt[MAX_TCPOPTLEN];
+ u_char opt[TCP_MAXOLEN];
unsigned optlen, hdrlen;
int idle, sendalot;
+#ifdef TTCP
+ struct rmxp_tao *taop;
+ struct rmxp_tao tao_noncached;
+#endif
/*
* Determine length of data that should be transmitted,
@@ -104,6 +106,17 @@ again:
win = min(tp->snd_wnd, tp->snd_cwnd);
flags = tcp_outflags[tp->t_state];
+#ifdef TTCP
+ /*
+ * Get standard flags, and add SYN or FIN if requested by 'hidden'
+ * state flags.
+ */
+ if (tp->t_flags & TF_NEEDFIN)
+ flags |= TH_FIN;
+ if (tp->t_flags & TF_NEEDSYN)
+ flags |= TH_SYN;
+#endif /* TTCP */
+
/*
* If in persist timeout with window of 0, send 1 byte.
* Otherwise, if window is small but nonzero
@@ -139,6 +152,26 @@ again:
len = min(so->so_snd.sb_cc, win) - off;
+#ifdef TTCP
+ if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
+ taop = &tao_noncached;
+ bzero(taop, sizeof(*taop));
+ }
+
+ /*
+ * Lop off SYN bit if it has already been sent. However, if this
+ * is SYN-SENT state and if segment contains data and if we don't
+ * know that foreign host supports TAO, suppress sending segment.
+ */
+ if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) {
+ flags &= ~TH_SYN;
+ off--, len++;
+ if (len > 0 && tp->t_state == TCPS_SYN_SENT &&
+ taop->tao_ccsent == 0)
+ return 0;
+ }
+#endif /* TTCP */
+
if (len < 0) {
/*
* If FIN has been sent but not acked,
@@ -179,11 +212,18 @@ again:
if (len == tp->t_maxseg)
goto send;
if ((idle || tp->t_flags & TF_NODELAY) &&
+#ifdef TTCP
+ (tp->t_flags & TF_NOPUSH) == 0 &&
+#endif
len + off >= so->so_snd.sb_cc)
goto send;
if (tp->t_force)
goto send;
+#ifdef TTCP
+ if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
+#else
if (len >= tp->max_sndwnd / 2)
+#endif
goto send;
if (SEQ_LT(tp->snd_nxt, tp->snd_max))
goto send;
@@ -216,7 +256,12 @@ again:
*/
if (tp->t_flags & TF_ACKNOW)
goto send;
+#ifdef TTCP
+ if ((flags & TH_RST) ||
+ ((flags & TH_SYN) && (tp->t_flags & TF_NEEDSYN) == 0))
+#else
if (flags & (TH_SYN|TH_RST))
+#endif
goto send;
if (SEQ_GT(tp->snd_up, tp->snd_una))
goto send;
@@ -279,10 +324,10 @@ send:
u_short mss;
opt[0] = TCPOPT_MAXSEG;
- opt[1] = 4;
- mss = htons((u_short) tcp_mss(tp, 0));
+ opt[1] = TCPOLEN_MAXSEG;
+ mss = htons((u_short) tcp_mssopt(tp));
bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss));
- optlen = 4;
+ optlen = TCPOLEN_MAXSEG;
if ((tp->t_flags & TF_REQ_SCALE) &&
((flags & TH_ACK) == 0 ||
@@ -303,8 +348,12 @@ send:
* and our peer have sent timestamps in our SYN's.
*/
if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
- (flags & TH_RST) == 0 &&
+ (flags & TH_RST) == 0 &&
+#ifdef TTCP
+ ((flags & TH_ACK) == 0 ||
+#else
((flags & (TH_SYN|TH_ACK)) == TH_SYN ||
+#endif
(tp->t_flags & TF_RCVD_TSTMP))) {
u_long *lp = (u_long *)(opt + optlen);
@@ -315,27 +364,108 @@ send:
optlen += TCPOLEN_TSTAMP_APPA;
}
+#ifdef TTCP
+ /*
+ * Send `CC-family' options if our side wants to use them (TF_REQ_CC),
+ * options are allowed (!TF_NOOPT) and it's not a RST.
+ */
+ if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
+ (flags & TH_RST) == 0) {
+ switch (flags & (TH_SYN|TH_ACK)) {
+ /*
+ * This is a normal ACK, send CC if we received CC before
+ * from our peer.
+ */
+ case TH_ACK:
+ if (!(tp->t_flags & TF_RCVD_CC))
+ break;
+ /*FALLTHROUGH*/
+
+ /*
+ * We can only get here in T/TCP's SYN_SENT* state, when
+ * we're a sending a non-SYN segment without waiting for
+ * the ACK of our SYN. A check above assures that we only
+ * do this if our peer understands T/TCP.
+ */
+ case 0:
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_CC;
+ opt[optlen++] = TCPOLEN_CC;
+ *(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);
+
+ optlen += 4;
+ break;
+
+ /*
+ * This is our initial SYN, check whether we have to use
+ * CC or CC.new.
+ */
+ case TH_SYN:
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_NOP;
+
+ if (taop->tao_ccsent != 0 &&
+ CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
+ opt[optlen++] = TCPOPT_CC;
+ taop->tao_ccsent = tp->cc_send;
+ } else {
+ opt[optlen++] = TCPOPT_CCNEW;
+ taop->tao_ccsent = 0;
+ }
+ opt[optlen++] = TCPOLEN_CC;
+ *(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);
+ optlen += 4;
+ break;
+
+ /*
+ * This is a SYN,ACK; send CC and CC.echo if we received
+ * CC from our peer.
+ */
+ case (TH_SYN|TH_ACK):
+ if (tp->t_flags & TF_RCVD_CC) {
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_CC;
+ opt[optlen++] = TCPOLEN_CC;
+ *(u_int32_t *)&opt[optlen] =
+ htonl(tp->cc_send);
+ optlen += 4;
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_NOP;
+ opt[optlen++] = TCPOPT_CCECHO;
+ opt[optlen++] = TCPOLEN_CC;
+ *(u_int32_t *)&opt[optlen] =
+ htonl(tp->cc_recv);
+ optlen += 4;
+ }
+ break;
+ }
+ }
+#endif /* TTCP */
+
hdrlen += optlen;
/*
* 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.
+ * Clear the FIN bit because we cut off the tail of
+ * the segment.
*/
- if (len > tp->t_maxseg - optlen) {
+ if (len + optlen > tp->t_maxopd) {
/*
* If there is still more to send, don't close the connection.
*/
flags &= ~TH_FIN;
- len = tp->t_maxseg - optlen;
+ len = tp->t_maxopd - optlen;
sendalot = 1;
- }
-
+ }
-#ifdef DIAGNOSTIC
+/*#ifdef DIAGNOSTIC*/
if (max_linkhdr + hdrlen > MHLEN)
panic("tcphdr too big");
-#endif
+/*#endif*/
/*
* Grab a header mbuf, attaching a copy of data to