- VERIFY(aid == SAE_ASSOCID_ANY || aid == SAE_ASSOCID_ALL ||
- aid == mpte->mpte_associd);
-
- /* terminate the association? */
- if (cid == SAE_CONNID_ANY || cid == SAE_CONNID_ALL) {
- /* if we're not detached, go thru socket state checks */
- if (!(mp_so->so_flags & SOF_PCBCLEARING)) {
- if (!(mp_so->so_state & (SS_ISCONNECTED|
- SS_ISCONNECTING))) {
- error = ENOTCONN;
- goto out;
- }
- if (mp_so->so_state & SS_ISDISCONNECTING) {
- error = EALREADY;
- goto out;
- }
- }
- MPT_LOCK(mp_tp);
- mptcp_cancel_all_timers(mp_tp);
- if (mp_tp->mpt_state < MPTCPS_ESTABLISHED) {
- (void) mptcp_close(mpte, mp_tp);
- MPT_UNLOCK(mp_tp);
- } else if ((mp_so->so_options & SO_LINGER) &&
- mp_so->so_linger == 0) {
- (void) mptcp_drop(mpte, mp_tp, 0);
- MPT_UNLOCK(mp_tp);
- } else {
- MPT_UNLOCK(mp_tp);
- soisdisconnecting(mp_so);
- sbflush(&mp_so->so_rcv);
- if (mptcp_usrclosed(mpte) != NULL)
- (void) mptcp_output(mpte);
- }
- } else {
- bool disconnect_embryonic_subflows = false;
- struct socket *so = NULL;
-
- TAILQ_FOREACH(mpts, &mpte->mpte_subflows, mpts_entry) {
- if (mpts->mpts_connid != cid)
- continue;
-
- MPTS_LOCK(mpts);
- /*
- * Check if disconnected subflow is the one used
- * to initiate MPTCP connection.
- * If it is and the connection is not yet join ready
- * disconnect all other subflows.
- */
- so = mpts->mpts_socket;
- if (!(mp_tp->mpt_flags & MPTCPF_JOIN_READY) &&
- so && !(so->so_flags & SOF_MP_SEC_SUBFLOW)) {
- disconnect_embryonic_subflows = true;
- }
-
- mpts->mpts_flags |= MPTSF_USER_DISCONNECT;
- mptcp_subflow_disconnect(mpte, mpts, FALSE);
- MPTS_UNLOCK(mpts);
- break;
- }
-
- if (mpts == NULL) {
- error = EINVAL;