+ if (len > tp->t_maxseg) {
+ len = tp->t_maxseg;
+ sendalot = 1;
+ }
+ if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
+ flags &= ~TH_FIN;
+ 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;
+ if (flags & (TH_SYN|TH_RST))
+ goto send;
+ if (SEQ_GT(tp->snd_up, tp->snd_una))
+ goto send;
+
+ /*
+ * Sender silly window avoidance. If connection is idle
+ * and can send all data, a maximum segment,
+ * at least a maximum default-size segment do it,
+ * or are forced, do it; otherwise don't bother.
+ * If peer's buffer is tiny, then send
+ * when window is at least half open.
+ * If retransmitting (possibly after persist timer forced us
+ * to send into a small window), then must resend.
+ */
+ if (len) {
+ if (len == tp->t_maxseg)
+ goto send;
+ if ((idle || tp->t_flags & TF_NODELAY) &&
+ len + off >= so->so_snd.sb_cc)
+ goto send;
+ if (tp->t_force)
+ goto send;
+ if (len >= tp->max_sndwnd / 2)
+ goto send;
+ if (SEQ_LT(tp->snd_nxt, tp->snd_max))
+ goto send;
+ }
+
+ /*
+ * Compare available window to amount of window
+ * known to peer (as advertised window less
+ * next expected input.) If the difference is 35% or more of the
+ * maximum possible window, then want to send a window update to peer.
+ */
+ if (win > 0) {
+ int adv = win - (tp->rcv_adv - tp->rcv_nxt);
+
+ if (100 * adv / so->so_rcv.sb_hiwat >= 35)
+ goto send;
+ if (adv >= 2 * tp->t_maxseg && so->so_rcv.sb_cc == 0)
+ goto send;
+ }
+
+ /*
+ * 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 small or 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 too small, there is data to transmit, and no
+ * retransmit or persist is pending, then go to persist state.
+ * If nothing happens soon, send when timer expires:
+ * if window is nonzero, transmit what we can,
+ * otherwise force out a byte.
+ */
+ if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 &&
+ tp->t_timer[TCPT_PERSIST] == 0) {
+ tp->t_rxtshift = 0;
+ tcp_setpersist(tp);
+ }
+
+ /*
+ * No reason to send a segment, just return.
+ */
+ return (0);
+
+send:
+ /*
+ * Grab a header mbuf, attaching a copy of data to
+ * be transmitted, and initialize the header from
+ * the template for sends on this connection.
+ */
+ MGET(m, M_DONTWAIT, MT_HEADER);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
+ m->m_len = sizeof (struct tcpiphdr);
+ if (len) {
+ if (tp->t_force && len == 1)
+ tcpstat.tcps_sndprobe++;
+ else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
+ tcpstat.tcps_sndrexmitpack++;
+ tcpstat.tcps_sndrexmitbyte += len;
+ } else {
+ tcpstat.tcps_sndpack++;
+ tcpstat.tcps_sndbyte += len;
+ }
+ m->m_next = m_copy(so->so_snd.sb_mb, off, len);
+ if (m->m_next == 0)
+ len = 0;
+ } else if (tp->t_flags & TF_ACKNOW)
+ tcpstat.tcps_sndacks++;
+ else if (flags & (TH_SYN|TH_FIN|TH_RST))
+ tcpstat.tcps_sndctrl++;
+ else if (SEQ_GT(tp->snd_up, tp->snd_una))
+ tcpstat.tcps_sndurg++;
+ else
+ tcpstat.tcps_sndwinup++;
+
+ ti = mtod(m, struct tcpiphdr *);
+ if (tp->t_template == 0)
+ panic("tcp_output");
+ bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr));
+
+ /*
+ * 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_max)
+ tp->snd_nxt--;
+ ti->ti_seq = htonl(tp->snd_nxt);
+ ti->ti_ack = htonl(tp->rcv_nxt);
+ /*
+ * Before ESTABLISHED, force sending of initial options
+ * unless TCP set to not do any options.
+ */
+ opt = NULL;
+ if (flags & TH_SYN && (tp->t_flags & TF_NOOPT) == 0) {
+ u_short mss;
+
+ mss = MIN(so->so_rcv.sb_hiwat / 2, tcp_mss(tp));
+ if (mss > IP_MSS - sizeof(struct tcpiphdr)) {
+ opt = tcp_initopt;
+ optlen = sizeof (tcp_initopt);
+ *(u_short *)(opt + 2) = htons(mss);