when resending FIN (for ack, etc.) but not retransmitting
SCCS-vsn: sys/netinet/tcp_output.c 6.18
SCCS-vsn: sys/netinet/tcp_var.h 6.7
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
- * @(#)tcp_output.c 6.17 (Berkeley) %G%
+ * @(#)tcp_output.c 6.18 (Berkeley) %G%
* and go to transmit state.
*/
if (tp->t_force) {
* and go to transmit state.
*/
if (tp->t_force) {
-if (win == 0 && off)
-log(7, "persist offset %d\n", off);
if (win == 0)
win = 1;
else {
if (win == 0)
win = 1;
else {
}
len = MIN(so->so_snd.sb_cc, win) - off;
}
len = MIN(so->so_snd.sb_cc, win) - off;
- if (len > tp->t_maxseg) {
- len = tp->t_maxseg;
- /*
- * Don't send more than one segment if retransmitting
- * (or persisting, but then we shouldn't be here).
- */
- if (tp->t_rxtshift == 0)
- sendalot = 1;
- }
-
flags = tcp_outflags[tp->t_state];
if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
flags &= ~TH_FIN;
flags = tcp_outflags[tp->t_state];
if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
flags &= ~TH_FIN;
/*
* If FIN has been sent but not acked,
* but we haven't been called to retransmit,
/*
* If FIN has been sent but not acked,
* but we haven't been called to retransmit,
- * len will be -1; no need to transmit now.
+ * len will be -1; transmit if acking, otherwise no need.
* Otherwise, window shrank after we sent into it.
* If window shrank to 0, cancel pending retransmit
* and pull snd_nxt back to (closed) window.
* Otherwise, window shrank after we sent into it.
* If window shrank to 0, cancel pending retransmit
* and pull snd_nxt back to (closed) window.
* If the window didn't close completely,
* just wait for an ACK.
*/
* If the window didn't close completely,
* just wait for an ACK.
*/
- if (flags & TH_FIN || win != 0)
+ if (flags & TH_FIN) {
+ if (tp->t_flags & TF_ACKNOW)
+ len = 0;
+ else
+ return (0);
+ } else if (win == 0) {
+ tp->t_timer[TCPT_REXMT] = 0;
+ tp->snd_nxt = tp->snd_una;
+ len = 0;
+ } else
- tp->t_timer[TCPT_REXMT] = 0;
- tp->snd_nxt = tp->snd_una;
- len = 0;
+ }
+ if (len > tp->t_maxseg) {
+ len = tp->t_maxseg;
+ /*
+ * Don't send more than one segment if retransmitting
+ * (or persisting, but then we shouldn't be here).
+ */
+ if (tp->t_rxtshift == 0)
+ sendalot = 1;
}
win = sbspace(&so->so_rcv);
}
win = sbspace(&so->so_rcv);
+
+ /*
+ * 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.
+ */
+ if (flags & TH_FIN &&
+ ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
+ goto send;
/*
* Send if we owe peer an ACK.
*/
if (tp->t_flags & TF_ACKNOW)
goto send;
/*
* Send if we owe peer an ACK.
*/
if (tp->t_flags & TF_ACKNOW)
goto send;
- if (flags & (TH_SYN|TH_RST|TH_FIN))
+ if (flags & (TH_SYN|TH_RST))
goto send;
if (SEQ_GT(tp->snd_up, tp->snd_una))
goto send;
goto send;
if (SEQ_GT(tp->snd_up, tp->snd_una))
goto send;
/*
* Fill in fields, remembering maximum advertised
* window for use in delaying messages about window sizes.
/*
* Fill in fields, remembering maximum advertised
* window for use in delaying messages about window sizes.
+ * If resending a FIN, be sure not to use a new sequence number.
+ if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
+ tp->snd_nxt != tp->snd_una)
+ tp->snd_nxt--;
ti->ti_seq = htonl(tp->snd_nxt);
ti->ti_ack = htonl(tp->rcv_nxt);
/*
ti->ti_seq = htonl(tp->snd_nxt);
ti->ti_ack = htonl(tp->rcv_nxt);
/*
/*
* Advance snd_nxt over sequence space of this segment.
*/
/*
* Advance snd_nxt over sequence space of this segment.
*/
- if (flags & (TH_SYN|TH_FIN))
+ if (flags & TH_SYN)
+ tp->snd_nxt++;
+ if (flags & TH_FIN) {
+ tp->t_flags |= TF_SENTFIN;
+ }
tp->snd_nxt += len;
if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
tp->snd_max = tp->snd_nxt;
tp->snd_nxt += len;
if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
tp->snd_max = tp->snd_nxt;
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
- * @(#)tcp_var.h 6.6 (Berkeley) %G%
+ * @(#)tcp_var.h 6.7 (Berkeley) %G%
short t_timer[TCPT_NTIMERS]; /* tcp timers */
short t_rxtshift; /* log(2) of rexmt exp. backoff */
struct mbuf *t_tcpopt; /* tcp options */
short t_timer[TCPT_NTIMERS]; /* tcp timers */
short t_rxtshift; /* log(2) of rexmt exp. backoff */
struct mbuf *t_tcpopt; /* tcp options */
- short t_maxseg; /* maximum segment size */
+ u_short t_maxseg; /* maximum segment size */
char t_force; /* 1 if forcing out a byte */
u_char t_flags;
#define TF_ACKNOW 0x01 /* ack peer immediately */
#define TF_DELACK 0x02 /* ack, but try to delay it */
#define TF_NODELAY 0x04 /* don't delay packets to coalesce */
#define TF_NOOPT 0x08 /* don't use tcp options */
char t_force; /* 1 if forcing out a byte */
u_char t_flags;
#define TF_ACKNOW 0x01 /* ack peer immediately */
#define TF_DELACK 0x02 /* ack, but try to delay it */
#define TF_NODELAY 0x04 /* don't delay packets to coalesce */
#define TF_NOOPT 0x08 /* don't use tcp options */
+#define TF_SENTFIN 0x10 /* have sent FIN */
struct tcpiphdr *t_template; /* skeletal packet for transmit */
struct inpcb *t_inpcb; /* back pointer to internet pcb */
/*
struct tcpiphdr *t_template; /* skeletal packet for transmit */
struct inpcb *t_inpcb; /* back pointer to internet pcb */
/*