+static int
+tcp_usr_connectx_common(struct socket *so, int af,
+ struct sockaddr_list **src_sl, struct sockaddr_list **dst_sl,
+ struct proc *p, uint32_t ifscope, associd_t aid, connid_t *pcid,
+ uint32_t flags, void *arg, uint32_t arglen)
+{
+#pragma unused(aid)
+#if !MPTCP
+#pragma unused(flags, arg, arglen)
+#endif /* !MPTCP */
+ struct sockaddr_entry *src_se = NULL, *dst_se = NULL;
+ struct inpcb *inp = sotoinpcb(so);
+ int error;
+
+ if (inp == NULL)
+ return (EINVAL);
+
+ VERIFY(dst_sl != NULL);
+
+ /* select source (if specified) and destination addresses */
+ error = in_selectaddrs(af, src_sl, &src_se, dst_sl, &dst_se);
+ if (error != 0)
+ return (error);
+
+ VERIFY(*dst_sl != NULL && dst_se != NULL);
+ VERIFY(src_se == NULL || *src_sl != NULL);
+ VERIFY(dst_se->se_addr->sa_family == af);
+ VERIFY(src_se == NULL || src_se->se_addr->sa_family == af);
+
+ /*
+ * We get here for 2 cases:
+ *
+ * a. From MPTCP, to connect a subflow. There is no need to
+ * bind the socket to the source address and/or interface,
+ * since everything has been taken care of by MPTCP. We
+ * simply check whether or not this is for the initial
+ * MPTCP connection attempt, or to join an existing one.
+ *
+ * b. From the socket layer, to connect a TCP. Perform the
+ * bind to source address and/or interface as necessary.
+ */
+#if MPTCP
+ if (flags & TCP_CONNREQF_MPTCP) {
+ struct mptsub_connreq *mpcr = arg;
+
+ /* Check to make sure this came down from MPTCP */
+ if (arg == NULL || arglen != sizeof (*mpcr))
+ return (EOPNOTSUPP);
+
+ switch (mpcr->mpcr_type) {
+ case MPTSUB_CONNREQ_MP_ENABLE:
+ break;
+ case MPTSUB_CONNREQ_MP_ADD:
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ } else
+#endif /* MPTCP */
+ {
+ /* bind socket to the specified interface, if requested */
+ if (ifscope != IFSCOPE_NONE &&
+ (error = inp_bindif(inp, ifscope, NULL)) != 0)
+ return (error);
+
+ /* if source address and/or port is specified, bind to it */
+ if (src_se != NULL) {
+ struct sockaddr *sa = src_se->se_addr;
+ error = sobindlock(so, sa, 0); /* already locked */
+ if (error != 0)
+ return (error);
+ }
+ }
+
+ switch (af) {
+ case AF_INET:
+ error = tcp_usr_connect(so, dst_se->se_addr, p);
+ break;
+#if INET6
+ case AF_INET6:
+ error = tcp6_usr_connect(so, dst_se->se_addr, p);
+ break;
+#endif /* INET6 */
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
+ if (error == 0 && pcid != NULL)
+ *pcid = 1; /* there is only 1 connection for a TCP */
+
+ return (error);
+}
+
+static int
+tcp_usr_connectx(struct socket *so, struct sockaddr_list **src_sl,
+ struct sockaddr_list **dst_sl, struct proc *p, uint32_t ifscope,
+ associd_t aid, connid_t *pcid, uint32_t flags, void *arg,
+ uint32_t arglen)
+{
+ return (tcp_usr_connectx_common(so, AF_INET, src_sl, dst_sl,
+ p, ifscope, aid, pcid, flags, arg, arglen));
+}
+