The branch main has been updated by tuexen:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5ac91821f5d7dd701752ba76041720d240a507c5

commit 5ac91821f5d7dd701752ba76041720d240a507c5
Author:     Michael Tuexen <tue...@freebsd.org>
AuthorDate: 2022-03-28 23:50:17 +0000
Commit:     Michael Tuexen <tue...@freebsd.org>
CommitDate: 2022-03-28 23:50:17 +0000

    sctp: get rid of stcb send lock
    
    Just use the stcb lock instead to simplify locking.
    
    Reported by:    syzbot+d00b202063150f85b...@syzkaller.appspotmail.com
    Reported by:    syzbot+87f268a0a6d2d6383...@syzkaller.appspotmail.com
    MFC after:      3 days
---
 sys/netinet/sctp_input.c        |  11 +-
 sys/netinet/sctp_lock_bsd.h     |  22 --
 sys/netinet/sctp_output.c       | 556 ++++++++++++++++++----------------------
 sys/netinet/sctp_pcb.c          |  12 +-
 sys/netinet/sctp_ss_functions.c |  70 +++--
 sys/netinet/sctp_sysctl.c       |  46 ++--
 sys/netinet/sctp_timer.c        |   4 +-
 sys/netinet/sctp_uio.h          |   2 +-
 sys/netinet/sctp_usrreq.c       |   4 -
 sys/netinet/sctputil.c          |  12 +-
 10 files changed, 333 insertions(+), 406 deletions(-)

diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 222b69102bef..91f55af7f598 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 cd20a730e5b8..2087db337a37 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 a46264cd3efe..2bc6ec9628cc 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 @@ one_more_time:
        /* 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 @@ one_more_time:
                        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 @@ one_more_time:
                         */
                        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 @@ one_more_time:
                                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 @@ one_more_time:
                        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 @@ one_more_time:
                }
        }
        some_taken = sp->some_taken;
-re_look:
        length = sp->length;
        if (sp->msg_is_complete) {
                /* The message is complete */
@@ -7307,31 +7278,9 @@ re_look:
                }
        } 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 @@ re_look:
 
        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 @@ dont_do_it:
                         * 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 @@ dont_do_it:
         * 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 @@ dont_do_it:
                /* 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 @@ dont_do_it:
        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 @@ skip_preblock:
        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 @@ skip_preblock:
         */
        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 @@ skip_preblock:
 #endif
                                goto do_a_copy_in;
                        }
*** 1040 LINES SKIPPED ***

Reply via email to