diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 222b69102bef70..91f55af7f5987a 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -179,6 +179,8 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) struct sctp_stream_queue_pending *sp; struct sctp_association *asoc; + SCTP_TCB_LOCK_ASSERT(stcb); + /* * This function returns if any stream has true unsent data on it. * Note that as it looks through it will clean up any places that @@ -186,7 +188,6 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) */ asoc = &stcb->asoc; unsent_data = 0; - SCTP_TCB_SEND_LOCK(stcb); if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) { /* Check to see if some data queued */ for (i = 0; i < stcb->asoc.streamoutcnt; i++) { @@ -234,7 +235,6 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked) } } } - SCTP_TCB_SEND_UNLOCK(stcb); return (unsent_data); } @@ -246,6 +246,8 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) struct sctp_nets *lnet; unsigned int i; + SCTP_TCB_LOCK_ASSERT(stcb); + init = &cp->init; asoc = &stcb->asoc; /* save off parameters */ @@ -263,7 +265,6 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) } } } - SCTP_TCB_SEND_LOCK(stcb); if (asoc->pre_open_streams > ntohs(init->num_inbound_streams)) { unsigned int newcnt; struct sctp_stream_out *outs; @@ -323,7 +324,6 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb) /* cut back the count */ asoc->pre_open_streams = newcnt; } - SCTP_TCB_SEND_UNLOCK(stcb); asoc->streamoutcnt = asoc->pre_open_streams; if (asoc->strmout) { for (i = 0; i < asoc->streamoutcnt; i++) { @@ -1808,8 +1808,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); /* send up all the data */ - SCTP_TCB_SEND_LOCK(stcb); - sctp_report_all_outbound(stcb, 0, SCTP_SO_LOCKED); for (i = 0; i < stcb->asoc.streamoutcnt; i++) { stcb->asoc.strmout[i].chunks_on_queues = 0; @@ -1896,7 +1894,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, */ LIST_INSERT_HEAD(head, stcb, sctp_asocs); - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_INP_WUNLOCK(stcb->sctp_ep); SCTP_INP_INFO_WUNLOCK(); asoc->total_flight = 0; diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h index cd20a730e5b811..2087db337a3737 100644 --- a/sys/netinet/sctp_lock_bsd.h +++ b/sys/netinet/sctp_lock_bsd.h @@ -337,28 +337,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) \ ((_inp)->inp_create_mtx.mtx_lock & MTX_CONTESTED) -#define SCTP_TCB_SEND_LOCK_INIT(_tcb) do { \ - mtx_init(&(_tcb)->tcb_send_mtx, "sctp-send-tcb", "tcbs", \ - MTX_DEF | MTX_DUPOK); \ -} while (0) - -#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) do { \ - mtx_destroy(&(_tcb)->tcb_send_mtx); \ -} while (0) - -#define SCTP_TCB_SEND_LOCK(_tcb) do { \ - mtx_lock(&(_tcb)->tcb_send_mtx); \ -} while (0) - -#define SCTP_TCB_SEND_UNLOCK(_tcb) do { \ - mtx_unlock(&(_tcb)->tcb_send_mtx); \ -} while (0) - -#define SCTP_TCB_SEND_LOCK_ASSERT(_tcb) do { \ - KASSERT(mtx_owned(&(_tcb)->tcb_send_mtx), \ - ("Don't own TCB send lock")); \ -} while (0) - /* * For the majority of things (once we have found the association) we will * lock the actual association mutex. This will protect all the assoiciation diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index a46264cd3efe8e..2bc6ec9628cc9e 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -6318,13 +6318,15 @@ static int sctp_msg_append(struct sctp_tcb *stcb, struct sctp_nets *net, struct mbuf *m, - struct sctp_sndrcvinfo *srcv, int hold_stcb_lock) + struct sctp_sndrcvinfo *srcv) { int error = 0; struct mbuf *at; struct sctp_stream_queue_pending *sp = NULL; struct sctp_stream_out *strm; + SCTP_TCB_LOCK_ASSERT(stcb); + /* * Given an mbuf chain, put it into the association send queue and * place it on the wheel @@ -6396,18 +6398,12 @@ sctp_msg_append(struct sctp_tcb *stcb, sctp_auth_key_acquire(stcb, sp->auth_keyid); sp->holds_key_ref = 1; } - if (hold_stcb_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } strm = &stcb->asoc.strmout[srcv->sinfo_stream]; sctp_snd_sb_alloc(stcb, sp->length); atomic_add_int(&stcb->asoc.stream_queue_cnt, 1); TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc, strm, sp); m = NULL; - if (hold_stcb_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } out_now: if (m) { sctp_m_freem(m); @@ -6656,9 +6652,8 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, atomic_subtract_int(&stcb->asoc.refcnt, 1); goto no_chunk_output; } else { - if (m) { - ret = sctp_msg_append(stcb, net, m, - &ca->sndrcv, 1); + if (m != NULL) { + ret = sctp_msg_append(stcb, net, m, &ca->sndrcv); } asoc = &stcb->asoc; if (ca->sndrcv.sinfo_flags & SCTP_EOF) { @@ -7166,7 +7161,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, int leading; uint8_t rcv_flags = 0; uint8_t some_taken; - uint8_t send_lock_up = 0; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; @@ -7174,10 +7168,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, /* sa_ignore FREED_MEMORY */ sp = TAILQ_FIRST(&strq->outqueue); if (sp == NULL) { - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } sp = TAILQ_FIRST(&strq->outqueue); if (sp) { goto one_more_time; @@ -7191,10 +7181,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, strq->last_msg_incomplete = 0; } to_move = 0; - if (send_lock_up) { - SCTP_TCB_SEND_UNLOCK(stcb); - send_lock_up = 0; - } goto out_of; } if ((sp->msg_is_complete) && (sp->length == 0)) { @@ -7206,16 +7192,11 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, */ if ((sp->put_last_out == 0) && (sp->discard_rest == 0)) { SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n"); - SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n", + SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", sp->sender_all_done, sp->length, sp->msg_is_complete, - sp->put_last_out, - send_lock_up); - } - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; + sp->put_last_out); } atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); @@ -7234,11 +7215,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, sp->data = NULL; } sctp_free_a_strmoq(stcb, sp, so_locked); - /* we can't be locked to it */ - if (send_lock_up) { - SCTP_TCB_SEND_UNLOCK(stcb); - send_lock_up = 0; - } /* back to get the next msg */ goto one_more_time; } else { @@ -7258,10 +7234,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, to_move = 0; goto out_of; } else if (sp->discard_rest) { - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } /* Whack down the size */ atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length); if ((stcb->sctp_socket != NULL) && @@ -7282,7 +7254,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, } } some_taken = sp->some_taken; -re_look: length = sp->length; if (sp->msg_is_complete) { /* The message is complete */ @@ -7307,31 +7278,9 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, } } else { to_move = sctp_can_we_split_this(stcb, length, space_left, frag_point, eeor_mode); - if (to_move) { - /*- - * We use a snapshot of length in case it - * is expanding during the compare. - */ - uint32_t llen; - - llen = length; - if (to_move >= llen) { - to_move = llen; - if (send_lock_up == 0) { - /*- - * We are taking all of an incomplete msg - * thus we need a send lock. - */ - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - if (sp->msg_is_complete) { - /* - * the sender finished the - * msg - */ - goto re_look; - } - } + if (to_move > 0) { + if (to_move >= length) { + to_move = length; } if (sp->some_taken == 0) { rcv_flags |= SCTP_DATA_FIRST_FRAG; @@ -7370,10 +7319,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, if (to_move >= length) { /* we think we can steal the whole thing */ - if ((sp->sender_all_done == 0) && (send_lock_up == 0)) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } if (to_move < sp->length) { /* bail, it changed */ goto dont_do_it; @@ -7467,10 +7412,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, * all the data if there is no leading space, so we * must put the data back and restore. */ - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; - } if (sp->data == NULL) { /* unsteal the data */ sp->data = chk->data; @@ -7579,8 +7520,8 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, * previous loop prior to padding. */ -#ifdef SCTP_ASOCLOG_OF_TSNS SCTP_TCB_LOCK_ASSERT(stcb); +#ifdef SCTP_ASOCLOG_OF_TSNS if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) { asoc->tsn_out_at = 0; asoc->tsn_out_wrapped = 1; @@ -7638,16 +7579,11 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, /* All done pull and kill the message */ if (sp->put_last_out == 0) { SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n"); - SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n", + SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", sp->sender_all_done, sp->length, sp->msg_is_complete, - sp->put_last_out, - send_lock_up); - } - if (send_lock_up == 0) { - SCTP_TCB_SEND_LOCK(stcb); - send_lock_up = 1; + sp->put_last_out); } atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); @@ -7672,9 +7608,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, TAILQ_INSERT_TAIL(&asoc->send_queue, chk, sctp_next); asoc->send_queue_cnt++; out_of: - if (send_lock_up) { - SCTP_TCB_SEND_UNLOCK(stcb); - } return (to_move); } @@ -12081,6 +12014,8 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, int can_send_out_req = 0; uint32_t seq; + SCTP_TCB_LOCK_ASSERT(stcb); + asoc = &stcb->asoc; if (asoc->stream_reset_outstanding) { /*- @@ -12184,7 +12119,6 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, * Ok now we proceed with copying the old out stuff and * initializing the new stuff. */ - SCTP_TCB_SEND_LOCK(stcb); stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, false); for (i = 0; i < stcb->asoc.streamoutcnt; i++) { TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); @@ -12238,7 +12172,6 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, } stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o; SCTP_FREE(oldstream, SCTP_M_STRMO); - SCTP_TCB_SEND_UNLOCK(stcb); } skip_stuff: if ((add_stream & 1) && (adding_o > 0)) { @@ -12489,7 +12422,7 @@ int sctp_lower_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, - struct mbuf *i_pak, + struct mbuf *top, struct mbuf *control, int flags, struct sctp_sndrcvinfo *srcv @@ -12500,7 +12433,6 @@ sctp_lower_sosend(struct socket *so, struct epoch_tracker et; ssize_t sndlen = 0, max_len, local_add_more; int error; - struct mbuf *top = NULL; int queue_only = 0, queue_only_for_init = 0; bool free_cnt_applied = false; int un_sent; @@ -12516,10 +12448,10 @@ sctp_lower_sosend(struct socket *so, int user_marks_eor; bool create_lock_applied = false; int nagle_applies = 0; - int some_on_control = 0; - int got_all_of_the_send = 0; + bool some_on_control; + bool got_all_of_the_send = false; bool hold_tcblock = false; - int non_blocking = 0; + bool non_blocking = false; ssize_t local_soresv = 0; uint16_t port; uint16_t sinfo_flags; @@ -12528,47 +12460,35 @@ sctp_lower_sosend(struct socket *so, error = 0; net = NULL; stcb = NULL; - asoc = NULL; t_inp = inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; - if (i_pak != NULL) { - SCTP_RELEASE_PKT(i_pak); - } - return (error); + goto out_unlocked; } - if ((uio == NULL) && (i_pak == NULL)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); + if ((uio == NULL) && (top == NULL)) { + error = EINVAL; + goto out_unlocked; } user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); atomic_add_int(&inp->total_sends, 1); if (uio != NULL) { if (uio->uio_resid < 0) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - return (EINVAL); + error = EINVAL; + goto out_unlocked; } sndlen = uio->uio_resid; } else { - top = SCTP_HEADER_TO_CHAIN(i_pak); - sndlen = SCTP_HEADER_LEN(i_pak); + sndlen = SCTP_HEADER_LEN(top); } SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n", - (void *)addr, - sndlen); + (void *)addr, sndlen); if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && SCTP_IS_LISTENING(inp)) { - /* The listener can NOT send */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); - error = ENOTCONN; + /* The listener can NOT send. */ + error = EINVAL; goto out_unlocked; } - /** - * Pre-screen address, if one is given the sin-len - * must be set correctly! - */ if (addr != NULL) { union sctp_sockstore *raddr = (union sctp_sockstore *)addr; @@ -12576,7 +12496,6 @@ sctp_lower_sosend(struct socket *so, #ifdef INET case AF_INET: if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -12586,7 +12505,6 @@ sctp_lower_sosend(struct socket *so, #ifdef INET6 case AF_INET6: if (raddr->sin6.sin6_len != sizeof(struct sockaddr_in6)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -12594,7 +12512,6 @@ sctp_lower_sosend(struct socket *so, break; #endif default: - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAFNOSUPPORT); error = EAFNOSUPPORT; goto out_unlocked; } @@ -12607,7 +12524,6 @@ sctp_lower_sosend(struct socket *so, sinfo_assoc_id = srcv->sinfo_assoc_id; if (INVALID_SINFO_FLAG(sinfo_flags) || PR_SCTP_INVALID_POLICY(sinfo_flags)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -12624,33 +12540,27 @@ sctp_lower_sosend(struct socket *so, sinfo_flags |= SCTP_EOF; } if (sinfo_flags & SCTP_SENDALL) { - /* its a sendall */ error = sctp_sendall(inp, uio, top, srcv); top = NULL; goto out_unlocked; } if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } - /* now we must find the assoc */ + /* Now we must find the association. */ + SCTP_INP_RLOCK(inp); if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_INP_RLOCK(inp); stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb != NULL) { SCTP_TCB_LOCK(stcb); hold_tcblock = true; - if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_INP_RUNLOCK(inp); - error = ENOTCONN; - goto out_unlocked; - } } SCTP_INP_RUNLOCK(inp); } else if (sinfo_assoc_id > SCTP_ALL_ASSOC) { - stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1); + stcb = sctp_findasoc_ep_asocid_locked(inp, sinfo_assoc_id, 1); + SCTP_INP_RUNLOCK(inp); if (stcb != NULL) { SCTP_TCB_LOCK_ASSERT(stcb); hold_tcblock = true; @@ -12661,9 +12571,8 @@ sctp_lower_sosend(struct socket *so, * increment it, and if we don't find a tcb * decrement it. */ - SCTP_INP_WLOCK(inp); SCTP_INP_INCR_REF(inp); - SCTP_INP_WUNLOCK(inp); + SCTP_INP_RUNLOCK(inp); stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); if (stcb == NULL) { SCTP_INP_WLOCK(inp); @@ -12673,7 +12582,10 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK_ASSERT(stcb); hold_tcblock = true; } + } else { + SCTP_INP_RUNLOCK(inp); } + #ifdef INVARIANTS if (stcb != NULL) { SCTP_TCB_LOCK_ASSERT(stcb); @@ -12688,14 +12600,11 @@ sctp_lower_sosend(struct socket *so, create_lock_applied = true; if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { - /* Should I really unlock ? */ - SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && (addr->sa_family == AF_INET6)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -12719,18 +12628,16 @@ sctp_lower_sosend(struct socket *so, SCTP_ASOC_CREATE_UNLOCK(inp); create_lock_applied = false; } - if (error) { + if (error != 0) { goto out_unlocked; } if (t_inp != inp) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); error = ENOTCONN; goto out_unlocked; } } if (stcb == NULL) { if (addr == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } else { @@ -12743,7 +12650,6 @@ sctp_lower_sosend(struct socket *so, * User asks to abort a non-existent assoc, * or EOF a non-existent assoc with no data */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } @@ -12756,7 +12662,8 @@ sctp_lower_sosend(struct socket *so, p, SCTP_INITIALIZE_AUTH_PARAMS); if (stcb == NULL) { - /* Error is setup for us in the call */ + /* error is setup for us in the call. */ + KASSERT(error != 0, ("error is 0 although stcb is NULL")); goto out_unlocked; } SCTP_TCB_LOCK_ASSERT(stcb); @@ -12776,6 +12683,8 @@ sctp_lower_sosend(struct socket *so, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); hold_tcblock = false; stcb = NULL; + KASSERT(error != 0, + ("error is 0 although sctp_process_cmsgs_for_init() indicated an error")); goto out_unlocked; } } @@ -12795,8 +12704,16 @@ sctp_lower_sosend(struct socket *so, KASSERT(hold_tcblock, ("hold_tcblock is false")); SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; - KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, - ("Association about to be freed")); + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* XXX: Could also be ECONNABORTED, not enough info. */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out_unlocked; + } /* Keep the stcb from being freed under our feet. */ atomic_add_int(&asoc->refcnt, 1); free_cnt_applied = true; @@ -12818,7 +12735,6 @@ sctp_lower_sosend(struct socket *so, net = NULL; if ((net == NULL) || ((port != 0) && (port != stcb->rport))) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -12833,7 +12749,6 @@ sctp_lower_sosend(struct socket *so, if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { if (sndlen > (ssize_t)asoc->smallest_mtu) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); error = EMSGSIZE; goto out_unlocked; } @@ -12841,7 +12756,7 @@ sctp_lower_sosend(struct socket *so, if (SCTP_SO_IS_NBIO(so) || (flags & (MSG_NBIO | MSG_DONTWAIT)) != 0 ) { - non_blocking = 1; + non_blocking = true; } /* would we block? */ if (non_blocking) { @@ -12855,11 +12770,12 @@ sctp_lower_sosend(struct socket *so, } if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + asoc->sb_send_resv)) || (asoc->chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK); - if (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so)) + if ((sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so)) && + (user_marks_eor == 0)) { error = EMSGSIZE; - else + } else { error = EWOULDBLOCK; + } goto out_unlocked; } asoc->sb_send_resv += (uint32_t)sndlen; @@ -12867,15 +12783,9 @@ sctp_lower_sosend(struct socket *so, atomic_add_int(&asoc->sb_send_resv, (int)sndlen); } local_soresv = sndlen; - if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); - error = ECONNRESET; - goto out_unlocked; - } /* Is the stream no. valid? */ if (srcv->sinfo_stream >= asoc->streamoutcnt) { /* Invalid stream number */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -12889,27 +12799,18 @@ sctp_lower_sosend(struct socket *so, } else { error = EINVAL; } - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error); goto out_unlocked; } if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { queue_only = 1; } - /* we are now done with all control */ - if (control) { - sctp_m_freem(control); - control = NULL; - } if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) || (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { - if (sinfo_flags & SCTP_ABORT) { - ; - } else { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); - error = ECONNRESET; + if ((sinfo_flags & SCTP_ABORT) == 0) { + error = EPIPE; goto out_unlocked; } } @@ -12923,6 +12824,8 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK_ASSERT(stcb); KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); /* Are we aborting? */ if (sinfo_flags & SCTP_ABORT) { @@ -12933,12 +12836,11 @@ sctp_lower_sosend(struct socket *so, SCTP_STAT_INCR(sctps_sends_with_abort); if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { - /* It has to be up before we abort */ - /* how big is the user initiated abort? */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + /* It has to be up before we abort. */ error = EINVAL; goto out; } + /* How big is the user initiated abort? */ if (top != NULL) { struct mbuf *cntm; @@ -12953,17 +12855,14 @@ sctp_lower_sosend(struct socket *so, tot_out = sndlen; tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); if (tot_demand > SCTP_DEFAULT_ADD_MORE) { - /* To big */ - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); error = EMSGSIZE; - goto out; + goto out_unlocked; } mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_NOWAIT, 1, MT_DATA); } if (mm == NULL) { - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); error = ENOMEM; - goto out; + goto out_unlocked; } max_out = asoc->smallest_mtu - sizeof(struct sctp_paramhdr); max_out -= sizeof(struct sctp_abort_msg); @@ -12981,8 +12880,18 @@ sctp_lower_sosend(struct socket *so, error = uiomove((caddr_t)ph, (int)tot_out, uio); SCTP_TCB_LOCK(stcb); hold_tcblock = true; - if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { sctp_m_freem(mm); + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* + * XXX: Could also be ECONNABORTED, + * not enough info. + */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } goto out_unlocked; } if (error != 0) { @@ -12993,6 +12902,7 @@ sctp_lower_sosend(struct socket *so, */ sctp_m_freem(mm); mm = NULL; + error = 0; } } else { if (sndlen != 0) { @@ -13022,6 +12932,8 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK_ASSERT(stcb); KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); /* Calculate the maximum we can send */ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); @@ -13033,22 +12945,20 @@ sctp_lower_sosend(struct socket *so, /* Unless E_EOR mode is on, we must make a send FIT in one call. */ if ((user_marks_eor == 0) && (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { - /* It will NEVER fit */ - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); + /* It will NEVER fit. */ error = EMSGSIZE; goto out_unlocked; } - if ((uio == NULL) && user_marks_eor) { + if ((uio == NULL) && (user_marks_eor != 0)) { /*- * We do not support eeor mode for * sending with mbuf chains (like sendfile). */ - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } - if (user_marks_eor) { + if (user_marks_eor != 0) { local_add_more = (ssize_t)min(SCTP_SB_LIMIT_SND(so), SCTP_BASE_SYSCTL(sctp_add_more_threshold)); } else { /*- @@ -13060,13 +12970,12 @@ sctp_lower_sosend(struct socket *so, if (non_blocking) { goto skip_preblock; } - if (((max_len <= local_add_more) && - ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) || + if (((max_len <= local_add_more) && ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) || (max_len == 0) || ((asoc->chunks_on_out_queue + asoc->stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { - /* No room right now ! */ - SOCKBUF_LOCK(&so->so_snd); + /* No room right now! */ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + SOCKBUF_LOCK(&so->so_snd); while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) || ((asoc->stream_queue_cnt + asoc->chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { SCTPDBG(SCTP_DEBUG_OUTPUT1, "pre_block limit:%u <(inq:%d + %zd) || (%d+%d > %d)\n", @@ -13084,29 +12993,41 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_UNLOCK(stcb); hold_tcblock = false; error = sbwait(&so->so_snd); - SCTP_TCB_LOCK(stcb); - hold_tcblock = true; - if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { - SOCKBUF_UNLOCK(&so->so_snd); - goto out_unlocked; - } - stcb->block_entry = NULL; if (error || so->so_error || be.error) { if (error == 0) { - if (so->so_error) + if (so->so_error != 0) { error = so->so_error; - if (be.error) { + } + if (be.error != 0) { error = be.error; } } SOCKBUF_UNLOCK(&so->so_snd); goto out_unlocked; } + SOCKBUF_UNLOCK(&so->so_snd); + SCTP_TCB_LOCK(stcb); + hold_tcblock = true; + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* + * XXX: Could also be ECONNABORTED, + * not enough info. + */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out_unlocked; + } + stcb->block_entry = NULL; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, asoc, asoc->total_output_queue_size); } inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + SOCKBUF_LOCK(&so->so_snd); } if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; @@ -13122,6 +13043,8 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK_ASSERT(stcb); KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); /* * sndlen covers for mbuf case uio_resid covers for the non-mbuf @@ -13129,42 +13052,48 @@ sctp_lower_sosend(struct socket *so, */ if (sndlen == 0) { if (sinfo_flags & SCTP_EOF) { - got_all_of_the_send = 1; + got_all_of_the_send = true; goto dataless_eof; } else { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out; } } + if (top == NULL) { struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strm; uint32_t sndout; - /* - * XXX: This will change soon, when the TCP send lock is - * retired. - */ - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = false; - SCTP_TCB_SEND_LOCK(stcb); if ((asoc->stream_locked) && (asoc->stream_locked_on != srcv->sinfo_stream)) { - SCTP_TCB_SEND_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out; } strm = &asoc->strmout[srcv->sinfo_stream]; if (strm->last_msg_incomplete == 0) { do_a_copy_in: - SCTP_TCB_SEND_UNLOCK(stcb); + SCTP_TCB_UNLOCK(stcb); + hold_tcblock = false; sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error); - if (error) { + SCTP_TCB_LOCK(stcb); + hold_tcblock = true; + if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || + (asoc->state & SCTP_STATE_WAS_ABORTED)) { + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* + * XXX: Could also be ECONNABORTED, + * not enough info. + */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out; + } + if (error != 0) { goto out; } - SCTP_TCB_SEND_LOCK(stcb); /* The out streams might be reallocated. */ strm = &asoc->strmout[srcv->sinfo_stream]; if (sp->msg_is_complete) { @@ -13202,74 +13131,79 @@ sctp_lower_sosend(struct socket *so, #endif goto do_a_copy_in; } - if (sp->processing) { - SCTP_TCB_SEND_UNLOCK(stcb); - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + if (sp->processing != 0) { error = EINVAL; goto out; } else { sp->processing = 1; } } - SCTP_TCB_SEND_UNLOCK(stcb); + + KASSERT(stcb != NULL, ("stcb is NULL")); + KASSERT(hold_tcblock, ("hold_tcblock is false")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + while (uio->uio_resid > 0) { /* How much room do we have? */ struct mbuf *new_tail, *mm; inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); - if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) + if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; - else + } else { max_len = 0; - + } if ((max_len > (ssize_t)SCTP_BASE_SYSCTL(sctp_add_more_threshold)) || - (max_len && (SCTP_SB_LIMIT_SND(so) < SCTP_BASE_SYSCTL(sctp_add_more_threshold))) || - (uio->uio_resid && (uio->uio_resid <= max_len))) { + ((max_len > 0) && (SCTP_SB_LIMIT_SND(so) < SCTP_BASE_SYSCTL(sctp_add_more_threshold))) || + (uio->uio_resid <= max_len)) { + SCTP_TCB_UNLOCK(stcb); + hold_tcblock = false; sndout = 0; new_tail = NULL; - if (hold_tcblock) { - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = false; - } mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail); - if ((mm == NULL) || error) { - if (mm) { - sctp_m_freem(mm); - } - SCTP_TCB_SEND_LOCK(stcb); - if (((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) && - ((asoc->state & SCTP_STATE_WAS_ABORTED) == 0) && - (sp != NULL)) { - sp->processing = 0; - } - SCTP_TCB_SEND_UNLOCK(stcb); - goto out; - } - /* Update the mbuf and count */ - SCTP_TCB_SEND_LOCK(stcb); + SCTP_TCB_LOCK(stcb); + hold_tcblock = true; if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || (asoc->state & SCTP_STATE_WAS_ABORTED)) { /* - * we need to get out. Peer probably + * We need to get out. Peer probably * aborted. */ sctp_m_freem(mm); if (asoc->state & SCTP_STATE_WAS_ABORTED) { - SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); + /* + * XXX: Could also be + * ECONNABORTED, not enough + * info. + */ error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out; + } + if ((mm == NULL) || (error != 0)) { + if (mm != NULL) { + sctp_m_freem(mm); + } + if (sp != NULL) { + sp->processing = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); goto out; } - if (sp->tail_mbuf) { - /* tack it to the end */ + /* Update the mbuf and count */ + if (sp->tail_mbuf != NULL) { + /* Tack it to the end. */ SCTP_BUF_NEXT(sp->tail_mbuf) = mm; - sp->tail_mbuf = new_tail; } else { - /* A stolen mbuf */ + /* A stolen mbuf. */ sp->data = mm; - sp->tail_mbuf = new_tail; } + sp->tail_mbuf = new_tail; sctp_snd_sb_alloc(stcb, sndout); atomic_add_int(&sp->length, sndout); if (sinfo_flags & SCTP_SACK_IMMEDIATELY) { @@ -13285,8 +13219,16 @@ sctp_lower_sosend(struct socket *so, } else { sp->msg_is_complete = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); } + + KASSERT(stcb != NULL, ("stcb is NULL")); + KASSERT(hold_tcblock, ("hold_tcblock is false")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + if (uio->uio_resid == 0) { /* got it all? */ continue; @@ -13297,10 +13239,6 @@ sctp_lower_sosend(struct socket *so, * This is ugly but we must assure locking * order */ - if (!hold_tcblock) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = true; - } sctp_prune_prsctp(stcb, asoc, srcv, (int)sndlen); inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) @@ -13310,29 +13248,17 @@ sctp_lower_sosend(struct socket *so, if (max_len > 0) { continue; } - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = false; } /* wait for space now */ if (non_blocking) { /* Non-blocking io in place out */ - SCTP_TCB_SEND_LOCK(stcb); if (sp != NULL) { sp->processing = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); - if (!hold_tcblock) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = true; - } goto skip_out_eof; } /* What about the INIT, send it maybe */ if (queue_only_for_init) { - if (!hold_tcblock) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = true; - } if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { /* a collision took us forward? */ queue_only = 0; @@ -13385,8 +13311,9 @@ sctp_lower_sosend(struct socket *so, asoc->total_flight, asoc->chunks_on_out_queue, asoc->total_flight_count); } - if (queue_only_for_init) + if (queue_only_for_init) { queue_only_for_init = 0; + } if ((queue_only == 0) && (nagle_applies == 0)) { /*- * need to start chunk output @@ -13396,25 +13323,10 @@ sctp_lower_sosend(struct socket *so, * and I don't need to start output :-D */ NET_EPOCH_ENTER(et); - if (!hold_tcblock) { - if (SCTP_TCB_TRYLOCK(stcb)) { - hold_tcblock = true; - sctp_chunk_output(inp, - stcb, - SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } - } else { - sctp_chunk_output(inp, - stcb, - SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); - } + sctp_chunk_output(inp, stcb, + SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); NET_EPOCH_EXIT(et); } - if (hold_tcblock) { - SCTP_TCB_UNLOCK(stcb); - hold_tcblock = false; - } - SOCKBUF_LOCK(&so->so_snd); /*- * This is a bit strange, but I think it will * work. The total_output_queue_size is locked and @@ -13430,6 +13342,7 @@ sctp_lower_sosend(struct socket *so, * wakeup flag in place. */ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); + SOCKBUF_LOCK(&so->so_snd); if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes + min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { @@ -13438,9 +13351,9 @@ sctp_lower_sosend(struct socket *so, } be.error = 0; stcb->block_entry = &be; + SCTP_TCB_UNLOCK(stcb); + hold_tcblock = false; error = sbwait(&so->so_snd); - stcb->block_entry = NULL; - if (error || so->so_error || be.error) { if (error == 0) { if (so->so_error) @@ -13450,37 +13363,50 @@ sctp_lower_sosend(struct socket *so, } } SOCKBUF_UNLOCK(&so->so_snd); - SCTP_TCB_SEND_LOCK(stcb); + SCTP_TCB_LOCK(stcb); + hold_tcblock = true; + stcb->block_entry = NULL; if (((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) && ((asoc->state & SCTP_STATE_WAS_ABORTED) == 0) && (sp != NULL)) { sp->processing = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); goto out_unlocked; } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { - sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, - asoc, asoc->total_output_queue_size); - } } SOCKBUF_UNLOCK(&so->so_snd); - SCTP_TCB_SEND_LOCK(stcb); + SCTP_TCB_LOCK(stcb); + hold_tcblock = true; + stcb->block_entry = NULL; if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || (asoc->state & SCTP_STATE_WAS_ABORTED)) { - SCTP_TCB_SEND_UNLOCK(stcb); - goto out_unlocked; + if (asoc->state & SCTP_STATE_WAS_ABORTED) { + /* + * XXX: Could also be ECONNABORTED, + * not enough info. + */ + error = ECONNRESET; + } else { + error = ENOTCONN; + } + goto out; + } + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { + sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, + asoc, asoc->total_output_queue_size); } - SCTP_TCB_SEND_UNLOCK(stcb); - } - SCTP_TCB_SEND_LOCK(stcb); - if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || - (asoc->state & SCTP_STATE_WAS_ABORTED)) { - SCTP_TCB_SEND_UNLOCK(stcb); - goto out_unlocked; } - if (sp) { + + KASSERT(stcb != NULL, ("stcb is NULL")); + KASSERT(hold_tcblock, ("hold_tcblock is false")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + + if (sp != NULL) { if (sp->msg_is_complete == 0) { strm->last_msg_incomplete = 1; if (asoc->idata_supported == 0) { @@ -13498,20 +13424,14 @@ sctp_lower_sosend(struct socket *so, strm->last_msg_incomplete = 0; asoc->stream_locked = 0; } - SCTP_TCB_SEND_UNLOCK(stcb); if (uio->uio_resid == 0) { - got_all_of_the_send = 1; - } - if (!hold_tcblock) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = true; + got_all_of_the_send = true; } } else { - /* We send in a 1, since we do have the stcb lock. */ - error = sctp_msg_append(stcb, net, top, srcv, 1); + error = sctp_msg_append(stcb, net, top, srcv); top = NULL; - if (sinfo_flags & SCTP_EOF) { - got_all_of_the_send = 1; + if ((sinfo_flags & SCTP_EOF) != 0) { + got_all_of_the_send = true; } } if (error != 0) { @@ -13524,10 +13444,11 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK_ASSERT(stcb); KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); /* EOF thing ? */ - if ((sinfo_flags & SCTP_EOF) && - (got_all_of_the_send == 1)) { + if ((sinfo_flags & SCTP_EOF) && got_all_of_the_send) { SCTP_STAT_INCR(sctps_sends_with_eof); error = 0; if (TAILQ_EMPTY(&asoc->send_queue) && @@ -13598,6 +13519,7 @@ sctp_lower_sosend(struct socket *so, NET_EPOCH_EXIT(et); hold_tcblock = false; stcb = NULL; + error = ECONNABORTED; goto out; } sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, @@ -13613,10 +13535,10 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK_ASSERT(stcb); KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); - if (!TAILQ_EMPTY(&asoc->control_send_queue)) { - some_on_control = 1; - } + some_on_control = !TAILQ_EMPTY(&asoc->control_send_queue); if (queue_only_for_init) { if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { /* a collision took us forward? */ @@ -13629,6 +13551,15 @@ sctp_lower_sosend(struct socket *so, queue_only = 1; } } + + KASSERT(stcb != NULL, ("stcb is NULL")); + KASSERT(hold_tcblock, ("hold_tcblock is false")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + if ((net->flight_size > net->cwnd) && (asoc->sctp_cmt_on_off == 0)) { SCTP_STAT_INCR(sctps_send_cwnd_avoid); @@ -13670,6 +13601,15 @@ sctp_lower_sosend(struct socket *so, asoc->total_flight, asoc->chunks_on_out_queue, asoc->total_flight_count); } + + KASSERT(stcb != NULL, ("stcb is NULL")); + KASSERT(hold_tcblock, ("hold_tcblock is false")); + SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); + NET_EPOCH_ENTER(et); if ((queue_only == 0) && (nagle_applies == 0) && (asoc->peers_rwnd && un_sent)) { sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); @@ -13696,6 +13636,10 @@ sctp_lower_sosend(struct socket *so, KASSERT(stcb != NULL, ("stcb is NULL")); KASSERT(hold_tcblock, ("hold_tcblock is false")); SCTP_TCB_LOCK_ASSERT(stcb); + KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, + ("Association about to be freed")); + KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, + ("Association was aborted")); out: out_unlocked: @@ -13716,9 +13660,6 @@ sctp_lower_sosend(struct socket *so, if (mtx_owned(&stcb->tcb_mtx)) { panic("Leaving with tcb mtx owned?"); } - if (mtx_owned(&stcb->tcb_send_mtx)) { - panic("Leaving with tcb send mtx owned?"); - } #endif } if (top != NULL) { @@ -13727,6 +13668,7 @@ sctp_lower_sosend(struct socket *so, if (control != NULL) { sctp_m_freem(control); } + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error); return (error); } diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 00bb25ecb96d84..16f634652287f6 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -4326,7 +4326,6 @@ sctp_aloc_assoc_locked(struct sctp_inpcb *inp, struct sockaddr *firstaddr, asoc = &stcb->asoc; SCTP_TCB_LOCK_INIT(stcb); - SCTP_TCB_SEND_LOCK_INIT(stcb); stcb->rport = rport; /* setup back pointer's */ stcb->sctp_ep = inp; @@ -4334,7 +4333,6 @@ sctp_aloc_assoc_locked(struct sctp_inpcb *inp, struct sockaddr *firstaddr, if ((err = sctp_init_asoc(inp, stcb, override_tag, initial_tsn, vrf_id, o_streams))) { /* failed */ SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_TCB_SEND_LOCK_DESTROY(stcb); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); SCTP_DECR_ASOC_COUNT(); *error = err; @@ -4365,7 +4363,6 @@ sctp_aloc_assoc_locked(struct sctp_inpcb *inp, struct sockaddr *firstaddr, SCTP_DECR_ASOC_COUNT(); SCTP_TCB_UNLOCK(stcb); SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_TCB_SEND_LOCK_DESTROY(stcb); LIST_REMOVE(stcb, sctp_asocs); LIST_REMOVE(stcb, sctp_tcbasocidhash); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); @@ -4702,6 +4699,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre struct socket *so; /* first, lets purge the entry from the hash table. */ + SCTP_TCB_LOCK_ASSERT(stcb); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 6); @@ -4713,7 +4711,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* there is no asoc, really TSNH :-0 */ return (1); } - SCTP_TCB_SEND_LOCK(stcb); if (stcb->asoc.alternate) { sctp_free_remote_addr(stcb->asoc.alternate); stcb->asoc.alternate = NULL; @@ -4748,7 +4745,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* nope, reader or writer in the way */ sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); /* no asoc destroyed */ - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 8); @@ -4826,7 +4822,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sctp_sorwakeup(inp, so); sctp_sowwakeup(inp, so); } - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); #ifdef SCTP_LOG_CLOSING @@ -4851,12 +4846,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre if (from_inpcbfree == SCTP_NORMAL_PROC) { atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); SCTP_INP_INFO_WLOCK(); SCTP_INP_WLOCK(inp); SCTP_TCB_LOCK(stcb); - SCTP_TCB_SEND_LOCK(stcb); } /* Double check the GONE flag */ if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || @@ -4904,7 +4897,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_INP_INFO_WUNLOCK(); SCTP_INP_WUNLOCK(inp); } - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); return (0); } @@ -5169,10 +5161,8 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Insert new items here :> */ /* Get rid of LOCK */ - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); SCTP_TCB_LOCK_DESTROY(stcb); - SCTP_TCB_SEND_LOCK_DESTROY(stcb); if (from_inpcbfree == SCTP_NORMAL_PROC) { SCTP_INP_INFO_WUNLOCK(); SCTP_INP_RLOCK(inp); diff --git a/sys/netinet/sctp_ss_functions.c b/sys/netinet/sctp_ss_functions.c index 23b1dc20e4cff9..793e936a36368b 100644 --- a/sys/netinet/sctp_ss_functions.c +++ b/sys/netinet/sctp_ss_functions.c @@ -53,7 +53,7 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc) { uint16_t i; - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); asoc->ss_data.locked_on_sending = NULL; asoc->ss_data.last_out_stream = NULL; @@ -75,7 +75,7 @@ static void sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, bool clear_values SCTP_UNUSED) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { struct sctp_stream_out *strq; @@ -92,6 +92,8 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, static void sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -109,7 +111,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); /* Add to wheel if not already on it and stream queue not empty */ if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { @@ -123,6 +125,8 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, static bool sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { + SCTP_TCB_LOCK_ASSERT(stcb); + return (TAILQ_EMPTY(&asoc->ss_data.out.wheel)); } @@ -131,7 +135,7 @@ sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); /* * Remove from wheel if stream queue is empty and actually is on the @@ -165,6 +169,8 @@ sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->ss_data.locked_on_sending != NULL) { KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, ("locked_on_sending %p not scheduled", @@ -223,6 +229,8 @@ sctp_ss_default_scheduled(struct sctp_tcb *stcb, KASSERT(strq != NULL, ("strq is NULL")); KASSERT(strq->ss_params.scheduled, ("strq %p is not scheduled", (void *)strq)); + SCTP_TCB_LOCK_ASSERT(stcb); + asoc->ss_data.last_out_stream = strq; if (asoc->idata_supported == 0) { sp = TAILQ_FIRST(&strq->outqueue); @@ -241,6 +249,8 @@ static void sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED) { + SCTP_TCB_LOCK_ASSERT(stcb); + /* Nothing to be done here */ return; } @@ -249,6 +259,8 @@ static int sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED) { + SCTP_TCB_LOCK_ASSERT(stcb); + /* Nothing to be done here */ return (-1); } @@ -257,6 +269,8 @@ static int sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED) { + SCTP_TCB_LOCK_ASSERT(stcb); + /* Nothing to be done here */ return (-1); } @@ -267,6 +281,8 @@ sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struc struct sctp_stream_out *strq; struct sctp_stream_queue_pending *sp; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->stream_queue_cnt != 1) { return (false); } @@ -292,7 +308,7 @@ sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc, { struct sctp_stream_out *strqt; - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { @@ -322,6 +338,8 @@ static struct sctp_stream_out * sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED, struct sctp_association *asoc) { + SCTP_TCB_LOCK_ASSERT(stcb); + return (asoc->ss_data.last_out_stream); } @@ -331,6 +349,8 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net { struct sctp_stream_out *strq, *strqt; + SCTP_TCB_LOCK_ASSERT(stcb); + strqt = asoc->ss_data.last_out_stream; KASSERT(strqt == NULL || strqt->ss_params.scheduled, ("last_out_stream %p not scheduled", (void *)strqt)); @@ -381,7 +401,7 @@ static void sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, bool clear_values) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { struct sctp_stream_out *strq; @@ -401,6 +421,8 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, static void sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -424,7 +446,7 @@ sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc, { struct sctp_stream_out *strqt; - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); /* Add to wheel if not already on it and stream queue not empty */ if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { @@ -450,7 +472,7 @@ static void sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); /* * Remove from wheel if stream queue is empty and actually is on the @@ -484,6 +506,8 @@ sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt, *strqn; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->ss_data.locked_on_sending != NULL) { KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, ("locked_on_sending %p not scheduled", @@ -538,6 +562,8 @@ static int sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED, struct sctp_stream_out *strq, uint16_t *value) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (strq == NULL) { return (-1); } @@ -549,6 +575,8 @@ static int sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, uint16_t value) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (strq == NULL) { return (-1); } @@ -566,7 +594,7 @@ static void sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, bool clear_values) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { struct sctp_stream_out *strq; @@ -586,6 +614,8 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, static void sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -607,7 +637,7 @@ static void sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) { if (strq->ss_params.ss.fb.rounds < 0) @@ -622,7 +652,7 @@ static void sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); /* * Remove from wheel if stream queue is empty and actually is on the @@ -656,6 +686,8 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq = NULL, *strqt; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->ss_data.locked_on_sending != NULL) { KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled, ("locked_on_sending %p not scheduled", @@ -699,6 +731,8 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, struct sctp_stream_out *strqt; int subtract; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->idata_supported == 0) { sp = TAILQ_FIRST(&strq->outqueue); if ((sp != NULL) && (sp->some_taken == 1)) { @@ -740,7 +774,7 @@ sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc) struct sctp_stream_queue_pending *sp; uint16_t i; - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); TAILQ_INIT(&asoc->ss_data.out.list); /* @@ -774,7 +808,7 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, { struct sctp_stream_queue_pending *sp; - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) { sp = TAILQ_FIRST(&asoc->ss_data.out.list); @@ -789,6 +823,8 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, static void sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + SCTP_TCB_LOCK_ASSERT(stcb); + if (with_strq != NULL) { if (stcb->asoc.ss_data.locked_on_sending == with_strq) { stcb->asoc.ss_data.locked_on_sending = strq; @@ -805,7 +841,7 @@ static void sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); if (!sp->scheduled) { TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next); @@ -817,6 +853,8 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, static bool sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { + SCTP_TCB_LOCK_ASSERT(stcb); + return (TAILQ_EMPTY(&asoc->ss_data.out.list)); } @@ -824,7 +862,7 @@ static void sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp) { - SCTP_TCB_SEND_LOCK_ASSERT(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); if (sp->scheduled) { TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); @@ -840,6 +878,8 @@ sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, struct sctp_stream_out *strq; struct sctp_stream_queue_pending *sp; + SCTP_TCB_LOCK_ASSERT(stcb); + if (asoc->ss_data.locked_on_sending) { return (asoc->ss_data.locked_on_sending); } diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 4acca03792c04b..66d42497832d54 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -855,8 +855,8 @@ sctp_sysctl_handle_trace_log_clear(SYSCTL_HANDLER_ARGS) return (error); \ } \ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \ - CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, \ - NULL, 0, sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC); + CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, \ + sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC); /* * sysctl definitions @@ -867,14 +867,10 @@ SCTP_UINT_SYSCTL(recvspace, sctp_recvspace, SCTPCTL_RECVSPACE) SCTP_UINT_SYSCTL(auto_asconf, sctp_auto_asconf, SCTPCTL_AUTOASCONF) SCTP_UINT_SYSCTL(ecn_enable, sctp_ecn_enable, SCTPCTL_ECN_ENABLE) SCTP_UINT_SYSCTL(pr_enable, sctp_pr_enable, SCTPCTL_PR_ENABLE) -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auth_enable, - CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_auth, "IU", - SCTPCTL_AUTH_ENABLE_DESC); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, - CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_asconf, "IU", - SCTPCTL_ASCONF_ENABLE_DESC); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auth_enable, CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, + NULL, 0, sctp_sysctl_handle_auth, "IU", SCTPCTL_AUTH_ENABLE_DESC); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, + NULL, 0, sctp_sysctl_handle_asconf, "IU", SCTPCTL_ASCONF_ENABLE_DESC); SCTP_UINT_SYSCTL(reconfig_enable, sctp_reconfig_enable, SCTPCTL_RECONFIG_ENABLE) SCTP_UINT_SYSCTL(nrsack_enable, sctp_nrsack_enable, SCTPCTL_NRSACK_ENABLE) SCTP_UINT_SYSCTL(pktdrop_enable, sctp_pktdrop_enable, SCTPCTL_PKTDROP_ENABLE) @@ -924,19 +920,13 @@ SCTP_UINT_SYSCTL(default_frag_interleave, sctp_default_frag_interleave, SCTPCTL_ SCTP_UINT_SYSCTL(mobility_base, sctp_mobility_base, SCTPCTL_MOBILITY_BASE) SCTP_UINT_SYSCTL(mobility_fasthandoff, sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF) #if defined(SCTP_LOCAL_TRACE_BUF) -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, log, - CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_trace_log, "S,sctplog"a - , "SCTP logging (struct sctp_log)"); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, clear_trace, - CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_trace_log_clear, "IU", - "Clear SCTP Logging buffer"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, log, CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_RD, + NULL, 0, sctp_sysctl_handle_trace_log, "S,sctplog", "SCTP logging (struct sctp_log)"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, clear_trace, CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, + NULL, 0, sctp_sysctl_handle_trace_log_clear, "IU", "Clear SCTP Logging buffer"); #endif -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_port, - CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_udp_tunneling, "IU", - SCTPCTL_UDP_TUNNELING_PORT_DESC); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_port, CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, + NULL, 0, sctp_sysctl_handle_udp_tunneling, "IU", SCTPCTL_UDP_TUNNELING_PORT_DESC); SCTP_UINT_SYSCTL(enable_sack_immediately, sctp_enable_sack_immediately, SCTPCTL_SACK_IMMEDIATELY_ENABLE) SCTP_UINT_SYSCTL(nat_friendly_init, sctp_inits_include_nat_friendly, SCTPCTL_NAT_FRIENDLY_INITS) SCTP_UINT_SYSCTL(vtag_time_wait, sctp_vtag_time_wait, SCTPCTL_TIME_WAIT) @@ -953,11 +943,7 @@ SCTP_UINT_SYSCTL(diag_info_code, sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE) #ifdef SCTP_DEBUG SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG) #endif -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, stats, - CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_stats, "S,sctpstat", - "SCTP statistics (struct sctp_stat)"); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, - CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - NULL, 0, sctp_sysctl_handle_assoclist, "S,xassoc", - "List of active SCTP associations"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_RW, + NULL, 0, sctp_sysctl_handle_stats, "S,sctpstat", "SCTP statistics (struct sctp_stat)"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_RD, + NULL, 0, sctp_sysctl_handle_assoclist, "S,xassoc", "List of active SCTP associations"); diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 17d834cd27347e..dee25676eead7c 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -1352,8 +1352,7 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, struct sctp_tcb *stcb) KASSERT(inp != NULL, ("inp is NULL")); KASSERT(stcb != NULL, ("stcb is NULL")); - - SCTP_TCB_SEND_LOCK(stcb); + SCTP_TCB_LOCK_ASSERT(stcb); KASSERT(TAILQ_EMPTY(&stcb->asoc.send_queue), ("send_queue not empty")); KASSERT(TAILQ_EMPTY(&stcb->asoc.sent_queue), ("sent_queue not empty")); @@ -1387,7 +1386,6 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, struct sctp_tcb *stcb) SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", stcb->asoc.stream_queue_cnt, chks_in_queue); } - SCTP_TCB_SEND_UNLOCK(stcb); if (chks_in_queue) { /* call the output queue function */ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index e974d88a333bcf..330a4529b0391f 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -1259,7 +1259,7 @@ int sctp_lower_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, - struct mbuf *i_pak, + struct mbuf *top, struct mbuf *control, int flags, struct sctp_sndrcvinfo *srcv diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 464337c534f248..15c30fe74904b9 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -4068,12 +4068,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - SCTP_TCB_SEND_LOCK(stcb); stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, true); stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; stcb->asoc.stream_scheduling_module = av->assoc_value; stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -4091,12 +4089,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_INP_RLOCK(inp); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { SCTP_TCB_LOCK(stcb); - SCTP_TCB_SEND_LOCK(stcb); stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, true); stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; stcb->asoc.stream_scheduling_module = av->assoc_value; stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); - SCTP_TCB_SEND_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 04a7e12f10eb0f..684bc68940b490 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1288,7 +1288,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); } - SCTP_TCB_SEND_LOCK(stcb); + SCTP_TCB_LOCK(stcb); for (i = 0; i < asoc->streamoutcnt; i++) { /* * inbound side must be set to 0xffff, also NOTE when we get @@ -1317,7 +1317,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->strmout[i].state = SCTP_STREAM_OPENING; } asoc->ss_functions.sctp_ss_init(stcb, asoc); - SCTP_TCB_SEND_UNLOCK(stcb); + SCTP_TCB_UNLOCK(stcb); /* Now the mapping array */ asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; @@ -4331,6 +4331,8 @@ sctp_abort_notification(struct sctp_tcb *stcb, bool from_peer, bool timeout, if (stcb == NULL) { return; } + SCTP_TCB_LOCK_ASSERT(stcb); + if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { @@ -4341,11 +4343,9 @@ sctp_abort_notification(struct sctp_tcb *stcb, bool from_peer, bool timeout, (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { return; } - SCTP_TCB_SEND_LOCK(stcb); SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED); /* Tell them we lost the asoc */ sctp_report_all_outbound(stcb, error, so_locked); - SCTP_TCB_SEND_UNLOCK(stcb); if (from_peer) { sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); } else { @@ -5041,6 +5041,8 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, int notdone; int do_wakeup_routine = 0; + SCTP_TCB_LOCK_ASSERT(stcb); + sid = tp1->rec.data.sid; mid = tp1->rec.data.mid; if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { @@ -5151,7 +5153,6 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, * Still no eom found. That means there is stuff left on the * stream out queue.. yuck. */ - SCTP_TCB_SEND_LOCK(stcb); strq = &stcb->asoc.strmout[sid]; sp = TAILQ_FIRST(&strq->outqueue); if (sp != NULL) { @@ -5233,7 +5234,6 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, sp->length = 0; } } - SCTP_TCB_SEND_UNLOCK(stcb); } if (do_wakeup_routine) { sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);