+ int inp_flags = inp ? inp->inp_flags : 0;
+ struct ip_out_args ipoa;
+ struct ip_moptions *imo;
+ int tos = IPTOS_UNSPEC;
+ int error = 0;
+#if CONTENT_FILTER
+ struct m_tag *cfil_tag = NULL;
+ bool cfil_faddr_use = false;
+ uint32_t cfil_so_state_change_cnt = 0;
+ uint32_t cfil_so_options = 0;
+ int cfil_inp_flags = 0;
+ struct sockaddr *cfil_faddr = NULL;
+ struct sockaddr_in *cfil_sin;
+#endif
+
+#if CONTENT_FILTER
+ /*
+ * If socket is subject to Content Filter and no addr is passed in,
+ * retrieve CFIL saved state from mbuf and use it if necessary.
+ */
+ if (so->so_cfil_db && dst == INADDR_ANY) {
+ cfil_tag = cfil_dgram_get_socket_state(m, &cfil_so_state_change_cnt, &cfil_so_options, &cfil_faddr, &cfil_inp_flags);
+ if (cfil_tag) {
+ cfil_sin = SIN(cfil_faddr);
+ flags = (cfil_so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
+ inp_flags = cfil_inp_flags;
+ if (inp && inp->inp_faddr.s_addr == INADDR_ANY) {
+ /*
+ * Socket is unconnected, simply use the saved faddr as 'addr' to go through
+ * the connect/disconnect logic.
+ */
+ dst = cfil_sin->sin_addr.s_addr;
+ } else if ((so->so_state_change_cnt != cfil_so_state_change_cnt) &&
+ (inp->inp_fport != cfil_sin->sin_port ||
+ inp->inp_faddr.s_addr != cfil_sin->sin_addr.s_addr)) {
+ /*
+ * Socket is connected but socket state and dest addr/port changed.
+ * We need to use the saved faddr and socket options.
+ */
+ cfil_faddr_use = true;
+ }
+ m_tag_free(cfil_tag);
+ }
+ }
+#endif
+
+ if (so->so_state & SS_ISCONNECTED) {
+ if (dst != INADDR_ANY) {
+ if (m != NULL) {
+ m_freem(m);
+ }
+ if (control != NULL) {
+ m_freem(control);
+ }
+ return EISCONN;
+ }
+ dst = cfil_faddr_use ? cfil_sin->sin_addr.s_addr : inp->inp_faddr.s_addr;
+ } else {
+ if (dst == INADDR_ANY) {
+ if (m != NULL) {
+ m_freem(m);
+ }
+ if (control != NULL) {
+ m_freem(control);
+ }
+ return ENOTCONN;
+ }
+ }
+
+ bzero(&ipoa, sizeof(ipoa));
+ ipoa.ipoa_boundif = IFSCOPE_NONE;
+ ipoa.ipoa_flags = IPOAF_SELECT_SRCIF;
+
+ int sotc = SO_TC_UNSPEC;
+ int netsvctype = _NET_SERVICE_TYPE_UNSPEC;
+
+
+ if (control != NULL) {
+ tos = so_tos_from_control(control);
+ sotc = so_tc_from_control(control, &netsvctype);
+
+ m_freem(control);
+ control = NULL;
+ }
+ if (sotc == SO_TC_UNSPEC) {
+ sotc = so->so_traffic_class;
+ netsvctype = so->so_netsvctype;
+ }
+
+ if (inp == NULL
+#if NECP
+ || (necp_socket_should_use_flow_divert(inp))
+#endif /* NECP */
+ ) {
+ if (m != NULL) {
+ m_freem(m);
+ }
+ VERIFY(control == NULL);
+ return inp == NULL ? EINVAL : EPROTOTYPE;
+ }
+
+ flags |= IP_OUTARGS;
+ /* If socket was bound to an ifindex, tell ip_output about it */
+ if (inp->inp_flags & INP_BOUND_IF) {
+ ipoa.ipoa_boundif = inp->inp_boundifp->if_index;
+ ipoa.ipoa_flags |= IPOAF_BOUND_IF;
+ }
+ if (INP_NO_CELLULAR(inp)) {
+ ipoa.ipoa_flags |= IPOAF_NO_CELLULAR;
+ }
+ if (INP_NO_EXPENSIVE(inp)) {
+ ipoa.ipoa_flags |= IPOAF_NO_EXPENSIVE;
+ }
+ if (INP_NO_CONSTRAINED(inp)) {
+ ipoa.ipoa_flags |= IPOAF_NO_CONSTRAINED;
+ }
+ if (INP_AWDL_UNRESTRICTED(inp)) {
+ ipoa.ipoa_flags |= IPOAF_AWDL_UNRESTRICTED;
+ }
+ ipoa.ipoa_sotc = sotc;
+ ipoa.ipoa_netsvctype = netsvctype;
+
+ if (inp->inp_flowhash == 0) {
+ inp->inp_flowhash = inp_calc_flowhash(inp);
+ }