+static int
+tcp_ip_output(struct socket *so, struct tcpcb *tp, struct mbuf *pkt,
+ int cnt, struct mbuf *opt, int flags, int sack_in_progress, int recwin)
+{
+ int error = 0;
+ boolean_t chain;
+ boolean_t unlocked = FALSE;
+ struct inpcb *inp = tp->t_inpcb;
+ struct ip_out_args ipoa;
+ struct route ro;
+#if CONFIG_OUT_IF
+ unsigned int outif;
+#endif /* CONFIG_OUT_IF */
+
+ /* If socket was bound to an ifindex, tell ip_output about it */
+ ipoa.ipoa_ifscope = (inp->inp_flags & INP_BOUND_IF) ?
+ inp->inp_boundif : IFSCOPE_NONE;
+ flags |= IP_OUTARGS;
+
+ /* Copy the cached route and take an extra reference */
+ inp_route_copyout(inp, &ro);
+
+ /*
+ * Data sent (as far as we can tell).
+ * If this advertises a larger window than any other segment,
+ * then remember the size of the advertised window.
+ * Make sure ACK/DELACK conditions are cleared before
+ * we unlock the socket.
+ */
+ if (recwin > 0 && SEQ_GT(tp->rcv_nxt + recwin, tp->rcv_adv))
+ tp->rcv_adv = tp->rcv_nxt + recwin;
+ tp->last_ack_sent = tp->rcv_nxt;
+ tp->t_flags &= ~(TF_ACKNOW | TF_DELACK);
+
+ /*
+ * If allowed, unlock TCP socket while in IP
+ * but only if the connection is established and
+ * if we're not sending from an upcall.
+ */
+ if (tcp_output_unlocked && ((so->so_flags & SOF_UPCALLINUSE) == 0) &&
+ (tp->t_state == TCPS_ESTABLISHED) && (sack_in_progress == 0)) {
+ unlocked = TRUE;
+ socket_unlock(so, 0);
+ }
+
+ /*
+ * Don't send down a chain of packets when:
+ * - TCP chaining is disabled
+ * - there is an IPsec rule set
+ * - there is a non default rule set for the firewall
+ */
+
+ chain = tcp_packet_chaining > 1
+#if IPSEC
+ && ipsec_bypass
+#endif
+#if IPFIREWALL
+ && (fw_enable == 0 || fw_bypass)
+#endif
+ ; // I'm important, not extraneous
+
+
+ while (pkt != NULL) {
+ struct mbuf *npkt = pkt->m_nextpkt;
+
+ if (!chain) {
+ pkt->m_nextpkt = NULL;
+ /*
+ * If we are not chaining, make sure to set the packet
+ * list count to 0 so that IP takes the right path;
+ * this is important for cases such as IPSec where a
+ * single mbuf might result in multiple mbufs as part
+ * of the encapsulation. If a non-zero count is passed
+ * down to IP, the head of the chain might change and
+ * we could end up skipping it (thus generating bogus
+ * packets). Fixing it in IP would be desirable, but
+ * for now this would do it.
+ */
+ cnt = 0;
+ }
+
+ error = ip_output_list(pkt, cnt, opt, &ro, flags, 0, &ipoa);
+ if (chain || error) {
+ /*
+ * If we sent down a chain then we are done since
+ * the callee had taken care of everything; else
+ * we need to free the rest of the chain ourselves.
+ */
+ if (!chain)
+ m_freem_list(npkt);
+ break;
+ }
+ pkt = npkt;
+ }
+
+ if (unlocked)
+ socket_lock(so, 0);
+
+ /* Synchronize cached PCB route */
+ inp_route_copyin(inp, &ro);
+
+ return (error);
+}
+