aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/tcp_output.c
diff options
context:
space:
mode:
authorMatthew Dillon <dillon@FreeBSD.org>2002-10-10 19:21:50 +0000
committerMatthew Dillon <dillon@FreeBSD.org>2002-10-10 19:21:50 +0000
commit28257b5cccce8b2e835710a878f3705e77563ce5 (patch)
tree1b749200addf62a3ee701a2340d28b71a18cb119 /sys/netinet/tcp_output.c
parentb2aa8b2a98fcd6f4e0abd19b3a2f72b4705aa640 (diff)
downloadsrc-28257b5cccce8b2e835710a878f3705e77563ce5.tar.gz
src-28257b5cccce8b2e835710a878f3705e77563ce5.zip
Update various comments mainly related to retransmit/FIN that I
documented while working on a previous bug. Fix a PERSIST bug. Properly account for a FIN sent during a PERSIST. MFC after: 7 days
Notes
Notes: svn path=/head/; revision=104815
Diffstat (limited to 'sys/netinet/tcp_output.c')
-rw-r--r--sys/netinet/tcp_output.c42
1 files changed, 36 insertions, 6 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 845aff8befa4..944e7eeff17c 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -215,6 +215,18 @@ again:
}
}
+ /*
+ * If snd_nxt == snd_max and we have transmitted a FIN, the
+ * offset will be > 0 even if so_snd.sb_cc is 0, resulting in
+ * a negative length. This can also occur when tcp opens up
+ * its congestion window while receiving additional duplicate
+ * acks after fast-retransmit because TCP will reset snd_nxt
+ * to snd_max after the fast-retransmit.
+ *
+ * In the normal retransmit-FIN-only case, however, snd_nxt will
+ * be set to snd_una, the offset will be 0, and the length may
+ * wind up 0.
+ */
len = (long)ulmin(so->so_snd.sb_cc, win) - off;
if ((taop = tcp_gettaocache(&tp->t_inpcb->inp_inc)) == NULL) {
@@ -252,7 +264,7 @@ again:
/*
* If FIN has been sent but not acked,
* but we haven't been called to retransmit,
- * len will be -1. Otherwise, window shrank
+ * len will be < 0. Otherwise, window shrank
* after we sent into it. If window shrank to 0,
* cancel pending retransmit, pull snd_nxt back
* to (closed) window, and set the persist timer
@@ -268,6 +280,12 @@ again:
tcp_setpersist(tp);
}
}
+
+ /*
+ * len will be >= 0 after this point. Truncate to the maximum
+ * segment length and ensure that FIN is removed if the length
+ * no longer contains the last data byte.
+ */
if (len > tp->t_maxseg) {
len = tp->t_maxseg;
sendalot = 1;
@@ -336,7 +354,8 @@ again:
}
/*
- * Send if we owe peer an ACK.
+ * Send if we owe the peer an ACK, RST, SYN, or urgent data. ACKNOW
+ * is also a catch-all for the retransmit timer timeout case.
*/
if (tp->t_flags & TF_ACKNOW)
goto send;
@@ -347,8 +366,7 @@ again:
goto send;
/*
* If our state indicates that FIN should be sent
- * and we have not yet done so, or we're retransmitting the FIN,
- * then we need to send.
+ * and we have not yet done so, then we need to send.
*/
if (flags & TH_FIN &&
((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
@@ -794,7 +812,7 @@ send:
/*
* Set retransmit timer if not currently set,
- * and not doing an ack or a keep-alive probe.
+ * and not doing a pure ack or a keep-alive probe.
* Initial value for retransmit timer is smoothed
* round-trip time + 2 * round-trip time variance.
* Initialize shift counter which is used for backoff
@@ -809,9 +827,21 @@ send:
callout_reset(tp->tt_rexmt, tp->t_rxtcur,
tcp_timer_rexmt, tp);
}
- } else
+ } else {
+ /*
+ * Persist case, update snd_max but since we are in
+ * persist mode (no window) we do not update snd_nxt.
+ */
+ int xlen = len;
+ if (flags & TH_SYN)
+ ++xlen;
+ if (flags & TH_FIN) {
+ ++xlen;
+ tp->t_flags |= TF_SENTFIN;
+ }
if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
tp->snd_max = tp->snd_nxt + len;
+ }
#ifdef TCPDEBUG
/*