+#if IPSEC
+ /*
+ * Pre-calculate here as we save another lookup into the darknesses
+ * of IPsec that way and can actually decide if TSO is ok.
+ */
+ if (ipsec_bypass == 0)
+ ipsec_optlen = ipsec_hdrsiz_tcp(tp);
+#endif
+ if (len > tp->t_maxseg) {
+ if ((tp->t_flags & TF_TSO) && tcp_do_tso && hwcksum_tx &&
+ ip_use_randomid && kipf_count == 0 &&
+ dlil_filter_disable_tso_count == 0 &&
+ tp->rcv_numsacks == 0 && sack_rxmit == 0 &&
+ sack_bytes_rxmt == 0 &&
+ inp->inp_options == NULL &&
+ inp->in6p_options == NULL
+#if IPSEC
+ && ipsec_optlen == 0
+#endif
+#if IPFIREWALL
+ && (fw_enable == 0 || fw_bypass)
+#endif
+ ) {
+ tso = 1;
+ sendalot = 0;
+ } else {
+ len = tp->t_maxseg;
+ sendalot = 1;
+ tso = 0;
+ }
+ }
+
+ /* Send one segment or less as a tail loss probe */
+ if (tp->t_flagsext & TF_SENT_TLPROBE) {
+ len = min(len, tp->t_maxseg);
+ sendalot = 0;
+ tso = 0;
+ }
+
+#if MPTCP
+ if ((so->so_flags & SOF_MP_SUBFLOW) &&
+ !(tp->t_mpflags & TMPF_TCP_FALLBACK)) {
+ int newlen = len;
+ if ((tp->t_state >= TCPS_ESTABLISHED) &&
+ ((tp->t_mpflags & TMPF_SND_MPPRIO) ||
+ (tp->t_mpflags & TMPF_SND_REM_ADDR) ||
+ (tp->t_mpflags & TMPF_SND_MPFAIL) ||
+ (tp->t_mpflags & TMPF_MPCAP_RETRANSMIT))) {
+ if (len > 0) {
+ len = 0;
+ }
+ sendalot = 1;
+ mptcp_acknow = TRUE;
+ } else {
+ mptcp_acknow = FALSE;
+ }
+ /*
+ * The contiguous bytes in the subflow socket buffer can be
+ * discontiguous at the MPTCP level. Since only one DSS
+ * option can be sent in one packet, reduce length to match
+ * the contiguous MPTCP level. Set sendalot to send remainder.
+ */
+ if (len > 0)
+ newlen = mptcp_adj_sendlen(so, off, len);
+ if (newlen < len) {
+ len = newlen;
+ sendalot = 1;
+ }
+ }
+#endif /* MPTCP */
+
+ /*
+ * If the socket is capable of doing unordered send,
+ * pull the amount of data that can be sent from the
+ * unordered priority queues to the serial queue in
+ * the socket buffer. If bytes are not yet available
+ * in the highest priority message, we may not be able
+ * to send any new data.
+ */
+ if (so->so_flags & SOF_ENABLE_MSGS) {
+ if ((off + len) >
+ so->so_msg_state->msg_serial_bytes) {
+ sbpull_unordered_data(so, off, len);
+
+ /* check if len needs to be modified */
+ if ((off + len) >
+ so->so_msg_state->msg_serial_bytes) {
+ len = so->so_msg_state->msg_serial_bytes - off;
+ if (len <= 0) {
+ len = 0;
+ tcpstat.tcps_msg_sndwaithipri++;
+ }
+ }
+ }
+ }
+
+ if (sack_rxmit) {
+ if (SEQ_LT(p->rxmit + len, tp->snd_una + so->so_snd.sb_cc))
+ flags &= ~TH_FIN;
+ } else {
+ if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
+ flags &= ~TH_FIN;
+ }
+
+ recwin = tcp_sbspace(tp);
+
+ /*
+ * Sender silly window avoidance. We transmit under the following
+ * conditions when len is non-zero:
+ *
+ * - we've timed out (e.g. persist timer)
+ * - we need to retransmit
+ * - We have a full segment (or more with TSO)
+ * - This is the last buffer in a write()/send() and we are
+ * either idle or running NODELAY
+ * - we have more then 1/2 the maximum send window's worth of
+ * data (receiver may be limited the window size)
+ */
+ if (len) {
+ if (tp->t_flagsext & TF_FORCE)
+ goto send;
+ if (SEQ_LT(tp->snd_nxt, tp->snd_max))
+ goto send;
+ if (sack_rxmit)
+ goto send;
+
+ /*
+ * Send new data on the connection only if it is
+ * not flow controlled
+ */
+ if (!INP_WAIT_FOR_IF_FEEDBACK(inp) ||
+ tp->t_state != TCPS_ESTABLISHED) {
+ if (len >= tp->t_maxseg)
+ goto send;
+ if (!(tp->t_flags & TF_MORETOCOME) &&
+ (idle || tp->t_flags & TF_NODELAY ||
+ tp->t_flags & TF_MAXSEGSNT ||
+ ALLOW_LIMITED_TRANSMIT(tp)) &&
+ (tp->t_flags & TF_NOPUSH) == 0 &&
+ len + off >= so->so_snd.sb_cc)
+ goto send;
+ if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
+ goto send;
+ } else {
+ tcpstat.tcps_fcholdpacket++;
+ }
+ }
+
+ /*
+ * Compare available window to amount of window
+ * known to peer (as advertised window less
+ * next expected input). If the difference is at least two
+ * max size segments, or at least 25% of the maximum possible
+ * window, then want to send a window update to peer.
+ * Skip this if the connection is in T/TCP half-open state.
+ */
+ if (recwin > 0 && !(tp->t_flags & TF_NEEDSYN)) {
+ /*
+ * "adv" is the amount we can increase the window,
+ * taking into account that we are limited by
+ * TCP_MAXWIN << tp->rcv_scale.
+ */
+ int32_t adv, oldwin = 0;
+ adv = imin(recwin, (int)TCP_MAXWIN << tp->rcv_scale) -
+ (tp->rcv_adv - tp->rcv_nxt);
+
+ if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt))
+ oldwin = tp->rcv_adv - tp->rcv_nxt;
+
+ if (adv >= (int32_t) (2 * tp->t_maxseg)) {
+ /*
+ * Update only if the resulting scaled value of
+ * the window changed, or if there is a change in
+ * the sequence since the last ack. This avoids
+ * what appears as dupe ACKS (see rdar://5640997)
+ *
+ * If streaming is detected avoid sending too many
+ * window updates. We will depend on the delack
+ * timer to send a window update when needed.
+ */
+ if (!(tp->t_flags & TF_STRETCHACK) &&
+ (tp->last_ack_sent != tp->rcv_nxt ||
+ ((oldwin + adv) >> tp->rcv_scale) >
+ (oldwin >> tp->rcv_scale))) {
+ goto send;
+ }
+
+ /*
+ * Make sure that the delayed ack timer is set if
+ * we delayed sending a window update because of
+ * streaming detection.
+ */
+ if ((tp->t_flags & TF_STRETCHACK) &&
+ !(tp->t_flags & TF_DELACK)) {
+ tp->t_flags |= TF_DELACK;
+ tp->t_timer[TCPT_DELACK] =
+ OFFSET_FROM_START(tp, tcp_delack);
+ }
+ }
+ if (4 * adv >= (int32_t) so->so_rcv.sb_hiwat)
+ goto send;