sctp: another cleanup
No functional change intended. MFC after: 1 week
This commit is contained in:
parent
15047a6509
commit
85e5480df9
@ -653,7 +653,10 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
|
||||
int
|
||||
sctp_disconnect(struct socket *so)
|
||||
{
|
||||
struct epoch_tracker et;
|
||||
struct sctp_inpcb *inp;
|
||||
struct sctp_association *asoc;
|
||||
struct sctp_tcb *stcb;
|
||||
|
||||
inp = (struct sctp_inpcb *)so->so_pcb;
|
||||
if (inp == NULL) {
|
||||
@ -661,134 +664,117 @@ sctp_disconnect(struct socket *so)
|
||||
return (ENOTCONN);
|
||||
}
|
||||
SCTP_INP_RLOCK(inp);
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
|
||||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
|
||||
if (LIST_EMPTY(&inp->sctp_asoc_list)) {
|
||||
/* No connection */
|
||||
KASSERT(inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE ||
|
||||
inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL,
|
||||
("Not a one-to-one style socket"));
|
||||
stcb = LIST_FIRST(&inp->sctp_asoc_list);
|
||||
if (stcb == NULL) {
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
|
||||
return (ENOTCONN);
|
||||
}
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
asoc = &stcb->asoc;
|
||||
if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
||||
/* We are about to be freed, out of here */
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
return (0);
|
||||
}
|
||||
NET_EPOCH_ENTER(et);
|
||||
if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
|
||||
(SCTP_SBAVAIL(&so->so_rcv) > 0)) {
|
||||
if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) {
|
||||
/* Left with Data unread */
|
||||
struct mbuf *op_err;
|
||||
|
||||
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
|
||||
sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
|
||||
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
|
||||
}
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
|
||||
/* No unlock tcb assoc is gone */
|
||||
NET_EPOCH_EXIT(et);
|
||||
return (0);
|
||||
}
|
||||
if (TAILQ_EMPTY(&asoc->send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(asoc->stream_queue_cnt == 0)) {
|
||||
/* there is nothing queued to send, so done */
|
||||
if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
|
||||
goto abort_anyway;
|
||||
}
|
||||
if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
|
||||
(SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
|
||||
/* only send SHUTDOWN 1st time thru */
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb, NULL);
|
||||
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* we still got (or just got) data to send, so set
|
||||
* SHUTDOWN_PENDING
|
||||
*/
|
||||
/*
|
||||
* XXX sockets draft says that SCTP_EOF should be sent with
|
||||
* no data. currently, we will allow user data to be sent
|
||||
* first and move to SHUTDOWN-PENDING
|
||||
*/
|
||||
SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
|
||||
SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
|
||||
}
|
||||
if (TAILQ_EMPTY(&asoc->send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
|
||||
struct mbuf *op_err;
|
||||
|
||||
abort_anyway:
|
||||
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
|
||||
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
|
||||
sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
|
||||
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
|
||||
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
|
||||
NET_EPOCH_EXIT(et);
|
||||
return (0);
|
||||
} else {
|
||||
struct epoch_tracker et;
|
||||
struct sctp_association *asoc;
|
||||
struct sctp_tcb *stcb;
|
||||
|
||||
stcb = LIST_FIRST(&inp->sctp_asoc_list);
|
||||
if (stcb == NULL) {
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
asoc = &stcb->asoc;
|
||||
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
||||
/* We are about to be freed, out of here */
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
return (0);
|
||||
}
|
||||
NET_EPOCH_ENTER(et);
|
||||
if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
|
||||
(SCTP_SBAVAIL(&so->so_rcv) > 0)) {
|
||||
if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) {
|
||||
/* Left with Data unread */
|
||||
struct mbuf *op_err;
|
||||
|
||||
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
|
||||
sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
|
||||
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
|
||||
}
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
|
||||
/* No unlock tcb assoc is gone */
|
||||
NET_EPOCH_EXIT(et);
|
||||
return (0);
|
||||
}
|
||||
if (TAILQ_EMPTY(&asoc->send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(asoc->stream_queue_cnt == 0)) {
|
||||
/* there is nothing queued to send, so done */
|
||||
if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
|
||||
goto abort_anyway;
|
||||
}
|
||||
if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
|
||||
(SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
|
||||
/* only send SHUTDOWN 1st time thru */
|
||||
struct sctp_nets *netp;
|
||||
|
||||
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
|
||||
sctp_stop_timers_for_shutdown(stcb);
|
||||
if (stcb->asoc.alternate) {
|
||||
netp = stcb->asoc.alternate;
|
||||
} else {
|
||||
netp = stcb->asoc.primary_destination;
|
||||
}
|
||||
sctp_send_shutdown(stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
|
||||
stcb->sctp_ep, stcb, netp);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
|
||||
stcb->sctp_ep, stcb, NULL);
|
||||
sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* we still got (or just got) data to send,
|
||||
* so set SHUTDOWN_PENDING
|
||||
*/
|
||||
/*
|
||||
* XXX sockets draft says that SCTP_EOF
|
||||
* should be sent with no data. currently,
|
||||
* we will allow user data to be sent first
|
||||
* and move to SHUTDOWN-PENDING
|
||||
*/
|
||||
SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
|
||||
if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
|
||||
SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
|
||||
}
|
||||
if (TAILQ_EMPTY(&asoc->send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
|
||||
struct mbuf *op_err;
|
||||
|
||||
abort_anyway:
|
||||
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
|
||||
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
|
||||
sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
|
||||
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
|
||||
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
|
||||
(SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
|
||||
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
|
||||
}
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
|
||||
NET_EPOCH_EXIT(et);
|
||||
return (0);
|
||||
} else {
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
|
||||
}
|
||||
}
|
||||
soisdisconnecting(so);
|
||||
NET_EPOCH_EXIT(et);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
return (0);
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
|
||||
}
|
||||
/* not reached */
|
||||
} else {
|
||||
/* UDP model does not support this */
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
soisdisconnecting(so);
|
||||
NET_EPOCH_EXIT(et);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user