- flags |= TH_FIN;
- tp->seq_fin = tp->snd_lst++;
- }
- } else {
- if (tp->tc_flags&TC_SYN_ACKED) {
- wind = tp->snd_una + tp->snd_wnd;
- tp->snd_lst = min(last, wind);
- if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
- tp->snd_lst -= len - 1024;
- if (tp->snd_lst >= wind)
- tp->t_persist = T_PERS;
- }
- if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
- tp->snd_lst = tp->snd_nxt + 1;
- forced = 1;
- }
- m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst);
- if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
- flags |= TH_EOL;
- if ((tp->tc_flags&TC_SND_FIN) && !forced &&
- tp->snd_lst == last &&
- (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
- flags |= TH_FIN;
- tp->seq_fin = tp->snd_lst++;
- }
- }
- if (tp->snd_nxt >= tp->snd_lst)
- return (0);
- if (tp->tc_flags & TC_SND_URG)
- flags |= TH_URG;
- sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
- if (!forced) {
- tp->t_rexmt = tp->t_xmtime;
- tp->t_rexmt_val = tp->snd_lst;
- if ((tp->tc_flags&TC_REXMT) == 0) {
- tp->t_rexmttl = T_REXMTTL;
- tp->t_rtl_val = tp->snd_lst;
- }
+ /*
+ * TCP window updates are not reliable, rather a polling protocol
+ * using ``persist'' packets is used to insure receipt of window
+ * updates. The three ``states'' for the output side are:
+ * idle not doing retransmits or persists
+ * persisting to move a zero window
+ * (re)transmitting and thereby not persisting
+ *
+ * tp->t_timer[TCPT_PERSIST]
+ * is set when we are in persist state.
+ * tp->t_force
+ * is set when we are called to send a persist packet.
+ * tp->t_timer[TCPT_REXMT]
+ * is set when we are retransmitting
+ * The output side is idle when both timers are zero.
+ *
+ * If send window is closed, there is data to transmit, and no
+ * retransmit or persist is pending, then go to persist state,
+ * arranging to force out a byte to get more current window information
+ * if nothing happens soon.
+ */
+ if (tp->snd_wnd == 0 && so->so_snd.sb_cc &&
+ tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) {
+ tp->t_rxtshift = 0;
+ tcp_setpersist(tp);