git: a4a31271cc7a - main - sctp: cleanup sctp_lower_sosend

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Sun, 20 Feb 2022 00:10:42 UTC
The branch main has been updated by tuexen:

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

commit a4a31271cc7a018b0a7120bf7d8fa40c39264914
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2022-02-20 00:09:30 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2022-02-20 00:09:30 +0000

    sctp: cleanup sctp_lower_sosend
    
    This is a preparation for retiring the tcp send lock in the
    next step.
    
    MFC after:      3 days
---
 sys/netinet/sctp_output.c | 481 +++++++++++++++++++++++-----------------------
 1 file changed, 242 insertions(+), 239 deletions(-)

diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 35a0406a5a9d..3d81fb2b4288 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -12502,7 +12502,7 @@ sctp_lower_sosend(struct socket *so,
 	int error;
 	struct mbuf *top = NULL;
 	int queue_only = 0, queue_only_for_init = 0;
-	int free_cnt_applied = 0;
+	bool free_cnt_applied = false;
 	int un_sent;
 	int now_filled = 0;
 	unsigned int inqueue_bytes = 0;
@@ -12514,11 +12514,11 @@ sctp_lower_sosend(struct socket *so,
 	struct sctp_association *asoc;
 	struct sctp_inpcb *t_inp;
 	int user_marks_eor;
-	int create_lock_applied = 0;
+	bool create_lock_applied = false;
 	int nagle_applies = 0;
 	int some_on_control = 0;
 	int got_all_of_the_send = 0;
-	int hold_tcblock = 0;
+	bool hold_tcblock = false;
 	int non_blocking = 0;
 	ssize_t local_soresv = 0;
 	uint16_t port;
@@ -12534,7 +12534,7 @@ sctp_lower_sosend(struct socket *so,
 	if (inp == NULL) {
 		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
 		error = EINVAL;
-		if (i_pak) {
+		if (i_pak != NULL) {
 			SCTP_RELEASE_PKT(i_pak);
 		}
 		return (error);
@@ -12545,7 +12545,7 @@ sctp_lower_sosend(struct socket *so,
 	}
 	user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
 	atomic_add_int(&inp->total_sends, 1);
-	if (uio) {
+	if (uio != NULL) {
 		if (uio->uio_resid < 0) {
 			SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
 			return (EINVAL);
@@ -12569,7 +12569,7 @@ sctp_lower_sosend(struct socket *so,
 	 * Pre-screen address, if one is given the sin-len
 	 * must be set correctly!
 	 */
-	if (addr) {
+	if (addr != NULL) {
 		union sctp_sockstore *raddr = (union sctp_sockstore *)addr;
 
 		switch (raddr->sa.sa_family) {
@@ -12598,10 +12598,11 @@ sctp_lower_sosend(struct socket *so,
 			error = EAFNOSUPPORT;
 			goto out_unlocked;
 		}
-	} else
+	} else {
 		port = 0;
+	}
 
-	if (srcv) {
+	if (srcv != NULL) {
 		sinfo_flags = srcv->sinfo_flags;
 		sinfo_assoc_id = srcv->sinfo_assoc_id;
 		if (INVALID_SINFO_FLAG(sinfo_flags) ||
@@ -12610,7 +12611,7 @@ sctp_lower_sosend(struct socket *so,
 			error = EINVAL;
 			goto out_unlocked;
 		}
-		if (srcv->sinfo_flags)
+		if (srcv->sinfo_flags != 0)
 			SCTP_STAT_INCR(sctps_sends_with_flags);
 	} else {
 		sinfo_flags = inp->def_send.sinfo_flags;
@@ -12638,17 +12639,23 @@ sctp_lower_sosend(struct socket *so,
 	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
 		SCTP_INP_RLOCK(inp);
 		stcb = LIST_FIRST(&inp->sctp_asoc_list);
-		if (stcb) {
+		if (stcb != NULL) {
 			SCTP_TCB_LOCK(stcb);
-			hold_tcblock = 1;
+			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) {
+	} else if (sinfo_assoc_id > SCTP_ALL_ASSOC) {
 		stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1);
 		if (stcb != NULL) {
-			hold_tcblock = 1;
+			SCTP_TCB_LOCK_ASSERT(stcb);
+			hold_tcblock = true;
 		}
-	} else if (addr) {
+	} else if (addr != NULL) {
 		/*-
 		 * Since we did not use findep we must
 		 * increment it, and if we don't find a tcb
@@ -12663,13 +12670,22 @@ sctp_lower_sosend(struct socket *so,
 			SCTP_INP_DECR_REF(inp);
 			SCTP_INP_WUNLOCK(inp);
 		} else {
-			hold_tcblock = 1;
+			SCTP_TCB_LOCK_ASSERT(stcb);
+			hold_tcblock = true;
 		}
 	}
-	if ((stcb == NULL) && (addr)) {
+#ifdef INVARIANTS
+	if (stcb != NULL) {
+		SCTP_TCB_LOCK_ASSERT(stcb);
+		KASSERT(hold_tcblock, ("tcb lock hold, hold_tcblock is false"));
+	} else {
+		KASSERT(!hold_tcblock, ("hold_tcblock is true, but stcb is NULL"));
+	}
+#endif
+	if ((stcb == NULL) && (addr != NULL)) {
 		/* Possible implicit send? */
 		SCTP_ASOC_CREATE_LOCK(inp);
-		create_lock_applied = 1;
+		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 ? */
@@ -12698,7 +12714,8 @@ sctp_lower_sosend(struct socket *so,
 			SCTP_INP_DECR_REF(inp);
 			SCTP_INP_WUNLOCK(inp);
 		} else {
-			hold_tcblock = 1;
+			SCTP_TCB_LOCK_ASSERT(stcb);
+			hold_tcblock = true;
 		}
 		if (error) {
 			goto out_unlocked;
@@ -12730,11 +12747,7 @@ sctp_lower_sosend(struct socket *so,
 			}
 			/* get an asoc/stcb struct */
 			vrf_id = inp->def_vrf_id;
-#ifdef INVARIANTS
-			if (create_lock_applied == 0) {
-				panic("Error, should hold create lock and I don't?");
-			}
-#endif
+			KASSERT(create_lock_applied, ("create_lock_applied is false"));
 			stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id,
 			    inp->sctp_ep.pre_open_stream_count,
 			    inp->sctp_ep.port,
@@ -12744,27 +12757,22 @@ sctp_lower_sosend(struct socket *so,
 				/* Error is setup for us in the call */
 				goto out_unlocked;
 			}
-			hold_tcblock = 1;
-			if (create_lock_applied) {
-				SCTP_ASOC_CREATE_UNLOCK(inp);
-				create_lock_applied = 0;
-			} else {
-				SCTP_PRINTF("Huh-3? create lock should have been on??\n");
-			}
+			SCTP_TCB_LOCK_ASSERT(stcb);
+			hold_tcblock = true;
+			SCTP_ASOC_CREATE_UNLOCK(inp);
+			create_lock_applied = false;
 			/*
 			 * Turn on queue only flag to prevent data from
 			 * being sent
 			 */
 			queue_only = 1;
-			asoc = &stcb->asoc;
 			SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
-			(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
-
-			if (control) {
+			(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
+			if (control != NULL) {
 				if (sctp_process_cmsgs_for_init(stcb, control, &error)) {
 					sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
 					    SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
-					hold_tcblock = 0;
+					hold_tcblock = false;
 					stcb = NULL;
 					goto out_unlocked;
 				}
@@ -12778,8 +12786,19 @@ sctp_lower_sosend(struct socket *so,
 			 * change it BEFORE we append the message.
 			 */
 		}
-	} else
-		asoc = &stcb->asoc;
+	}
+
+	KASSERT(!create_lock_applied, ("create_lock_applied is true"));
+	KASSERT(stcb != NULL, ("stcb is NULL"));
+	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"));
+	/* Keep the stcb from being freed under our feet. */
+	atomic_add_int(&asoc->refcnt, 1);
+	free_cnt_applied = true;
+
 	if (srcv == NULL) {
 		srcv = (struct sctp_sndrcvinfo *)&asoc->def_send;
 		sinfo_flags = srcv->sinfo_flags;
@@ -12791,7 +12810,7 @@ sctp_lower_sosend(struct socket *so,
 		}
 	}
 	if (sinfo_flags & SCTP_ADDR_OVER) {
-		if (addr)
+		if (addr != NULL)
 			net = sctp_findnet(stcb, addr);
 		else
 			net = NULL;
@@ -12802,16 +12821,13 @@ sctp_lower_sosend(struct socket *so,
 			goto out_unlocked;
 		}
 	} else {
-		if (stcb->asoc.alternate) {
-			net = stcb->asoc.alternate;
+		if (asoc->alternate != NULL) {
+			net = asoc->alternate;
 		} else {
-			net = stcb->asoc.primary_destination;
+			net = asoc->primary_destination;
 		}
 	}
 	atomic_add_int(&stcb->total_sends, 1);
-	/* Keep the stcb from being freed under our feet */
-	atomic_add_int(&asoc->refcnt, 1);
-	free_cnt_applied = 1;
 
 	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) {
 		if (sndlen > (ssize_t)asoc->smallest_mtu) {
@@ -12829,18 +12845,14 @@ sctp_lower_sosend(struct socket *so,
 	if (non_blocking) {
 		ssize_t amount;
 
-		if (hold_tcblock == 0) {
-			SCTP_TCB_LOCK(stcb);
-			hold_tcblock = 1;
-		}
-		inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+		inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
 		if (user_marks_eor == 0) {
 			amount = sndlen;
 		} else {
 			amount = 1;
 		}
-		if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + stcb->asoc.sb_send_resv)) ||
-		    (stcb->asoc.chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+		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))
 				error = EMSGSIZE;
@@ -12848,22 +12860,16 @@ sctp_lower_sosend(struct socket *so,
 				error = EWOULDBLOCK;
 			goto out_unlocked;
 		}
-		stcb->asoc.sb_send_resv += (uint32_t)sndlen;
-		SCTP_TCB_UNLOCK(stcb);
-		hold_tcblock = 0;
+		asoc->sb_send_resv += (uint32_t)sndlen;
 	} else {
-		atomic_add_int(&stcb->asoc.sb_send_resv, (int)sndlen);
+		atomic_add_int(&asoc->sb_send_resv, (int)sndlen);
 	}
 	local_soresv = sndlen;
-	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+	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;
 	}
-	if (create_lock_applied) {
-		SCTP_ASOC_CREATE_UNLOCK(inp);
-		create_lock_applied = 0;
-	}
 	/* Is the stream no. valid? */
 	if (srcv->sinfo_stream >= asoc->streamoutcnt) {
 		/* Invalid stream number */
@@ -12906,12 +12912,20 @@ sctp_lower_sosend(struct socket *so,
 		}
 	}
 	/* Ok, we will attempt a msgsnd :> */
-	if (p) {
+	if (p != NULL) {
 		p->td_ru.ru_msgsnd++;
 	}
+
+	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"));
+
 	/* Are we aborting? */
 	if (sinfo_flags & SCTP_ABORT) {
 		struct mbuf *mm;
+		struct sctp_paramhdr *ph;
 		ssize_t tot_demand, tot_out = 0, max_out;
 
 		SCTP_STAT_INCR(sctps_sends_with_abort);
@@ -12923,19 +12937,15 @@ sctp_lower_sosend(struct socket *so,
 			error = EINVAL;
 			goto out;
 		}
-		if (hold_tcblock) {
-			SCTP_TCB_UNLOCK(stcb);
-			hold_tcblock = 0;
-		}
-		if (top) {
-			struct mbuf *cntm = NULL;
+		if (top != NULL) {
+			struct mbuf *cntm;
 
-			mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_WAITOK, 1, MT_DATA);
 			if (sndlen != 0) {
 				for (cntm = top; cntm; cntm = SCTP_BUF_NEXT(cntm)) {
 					tot_out += SCTP_BUF_LEN(cntm);
 				}
 			}
+			mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
 		} else {
 			/* Must fit in a MTU */
 			tot_out = sndlen;
@@ -12946,7 +12956,7 @@ sctp_lower_sosend(struct socket *so,
 				error = EMSGSIZE;
 				goto out;
 			}
-			mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_WAITOK, 1, MT_DATA);
+			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);
@@ -12958,43 +12968,41 @@ sctp_lower_sosend(struct socket *so,
 		if (tot_out > max_out) {
 			tot_out = max_out;
 		}
-		if (mm) {
-			struct sctp_paramhdr *ph;
-
-			/* now move forward the data pointer */
-			ph = mtod(mm, struct sctp_paramhdr *);
-			ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
-			ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out));
-			ph++;
-			SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr));
-			if (top == NULL) {
-				error = uiomove((caddr_t)ph, (int)tot_out, uio);
-				if (error) {
-					/*-
-					 * Here if we can't get his data we
-					 * still abort we just don't get to
-					 * send the users note :-0
-					 */
-					sctp_m_freem(mm);
-					mm = NULL;
-				}
-			} else {
-				if (sndlen != 0) {
-					SCTP_BUF_NEXT(mm) = top;
-				}
-			}
-		}
-		if (hold_tcblock == 0) {
+		ph = mtod(mm, struct sctp_paramhdr *);
+		ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
+		ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out));
+		ph++;
+		SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr));
+		if (top == NULL) {
+			SCTP_TCB_UNLOCK(stcb);
+			hold_tcblock = false;
+			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) {
+				sctp_m_freem(mm);
+				goto out_unlocked;
+			}
+			if (error != 0) {
+				/*-
+				 * Here if we can't get his data we
+				 * still abort we just don't get to
+				 * send the users note :-0
+				 */
+				sctp_m_freem(mm);
+				mm = NULL;
+			}
+		} else {
+			if (sndlen != 0) {
+				SCTP_BUF_NEXT(mm) = top;
+			}
 		}
-		atomic_subtract_int(&stcb->asoc.refcnt, 1);
-		free_cnt_applied = 0;
+		atomic_subtract_int(&asoc->refcnt, 1);
+		free_cnt_applied = false;
 		/* release this lock, otherwise we hang on ourselves */
 		NET_EPOCH_ENTER(et);
 		sctp_abort_an_association(stcb->sctp_ep, stcb, mm, false, SCTP_SO_LOCKED);
 		NET_EPOCH_EXIT(et);
-		/* now relock the stcb so everything is sane */
-		hold_tcblock = 0;
 		stcb = NULL;
 		/*
 		 * In this case top is already chained to mm avoid double
@@ -13006,24 +13014,20 @@ sctp_lower_sosend(struct socket *so,
 		}
 		goto out_unlocked;
 	}
+
+	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"));
+
 	/* Calculate the maximum we can send */
-	inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+	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) {
 		max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
 	} else {
 		max_len = 0;
 	}
-	if (hold_tcblock) {
-		SCTP_TCB_UNLOCK(stcb);
-		hold_tcblock = 0;
-	}
-	if (asoc->strmout == NULL) {
-		/* huh? software error */
-		SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
-		error = EFAULT;
-		goto out_unlocked;
-	}
-
 	/* 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))) {
@@ -13057,25 +13061,33 @@ sctp_lower_sosend(struct socket *so,
 	if (((max_len <= local_add_more) &&
 	    ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) ||
 	    (max_len == 0) ||
-	    ((stcb->asoc.chunks_on_out_queue + stcb->asoc.stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+	    ((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);
-		inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+		inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
 		while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) ||
-		    ((stcb->asoc.stream_queue_cnt + stcb->asoc.chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+		    ((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",
 			    (unsigned int)SCTP_SB_LIMIT_SND(so),
 			    inqueue_bytes,
 			    local_add_more,
-			    stcb->asoc.stream_queue_cnt,
-			    stcb->asoc.chunks_on_out_queue,
+			    asoc->stream_queue_cnt,
+			    asoc->chunks_on_out_queue,
 			    SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue));
 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
 				sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, asoc, sndlen);
 			}
 			be.error = 0;
 			stcb->block_entry = &be;
+			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) {
@@ -13090,13 +13102,9 @@ sctp_lower_sosend(struct socket *so,
 			}
 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
 				sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK,
-				    asoc, stcb->asoc.total_output_queue_size);
+				    asoc, asoc->total_output_queue_size);
 			}
-			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
-				SOCKBUF_UNLOCK(&so->so_snd);
-				goto out_unlocked;
-			}
-			inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+			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) {
 			max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
@@ -13107,9 +13115,12 @@ sctp_lower_sosend(struct socket *so,
 	}
 
 skip_preblock:
-	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
-		goto out_unlocked;
-	}
+	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"));
+
 	/*
 	 * sndlen covers for mbuf case uio_resid covers for the non-mbuf
 	 * case NOTE: uio will be null when top/mbuf is passed
@@ -13129,6 +13140,12 @@ skip_preblock:
 		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)) {
@@ -13137,7 +13154,7 @@ skip_preblock:
 			error = EINVAL;
 			goto out;
 		}
-		strm = &stcb->asoc.strmout[srcv->sinfo_stream];
+		strm = &asoc->strmout[srcv->sinfo_stream];
 		if (strm->last_msg_incomplete == 0) {
 	do_a_copy_in:
 			SCTP_TCB_SEND_UNLOCK(stcb);
@@ -13147,7 +13164,7 @@ skip_preblock:
 			}
 			SCTP_TCB_SEND_LOCK(stcb);
 			/* The out streams might be reallocated. */
-			strm = &stcb->asoc.strmout[srcv->sinfo_stream];
+			strm = &asoc->strmout[srcv->sinfo_stream];
 			if (sp->msg_is_complete) {
 				strm->last_msg_incomplete = 0;
 				asoc->stream_locked = 0;
@@ -13157,7 +13174,7 @@ skip_preblock:
 				 * interrupt.
 				 */
 				strm->last_msg_incomplete = 1;
-				if (stcb->asoc.idata_supported == 0) {
+				if (asoc->idata_supported == 0) {
 					asoc->stream_locked = 1;
 					asoc->stream_locked_on = srcv->sinfo_stream;
 				}
@@ -13170,7 +13187,7 @@ skip_preblock:
 			}
 			sp->processing = 1;
 			TAILQ_INSERT_TAIL(&strm->outqueue, sp, next);
-			stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp);
+			asoc->ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp);
 		} else {
 			sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead);
 			if (sp == NULL) {
@@ -13197,7 +13214,7 @@ skip_preblock:
 			/* How much room do we have? */
 			struct mbuf *new_tail, *mm;
 
-			inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+			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)
 				max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
 			else
@@ -13210,7 +13227,7 @@ skip_preblock:
 				new_tail = NULL;
 				if (hold_tcblock) {
 					SCTP_TCB_UNLOCK(stcb);
-					hold_tcblock = 0;
+					hold_tcblock = false;
 				}
 				mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail);
 				if ((mm == NULL) || error) {
@@ -13218,8 +13235,8 @@ skip_preblock:
 						sctp_m_freem(mm);
 					}
 					SCTP_TCB_SEND_LOCK(stcb);
-					if (((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
-					    ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) == 0) &&
+					if (((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
+					    ((asoc->state & SCTP_STATE_WAS_ABORTED) == 0) &&
 					    (sp != NULL)) {
 						sp->processing = 0;
 					}
@@ -13228,14 +13245,14 @@ skip_preblock:
 				}
 				/* Update the mbuf and count */
 				SCTP_TCB_SEND_LOCK(stcb);
-				if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
-				    (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+				if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+				    (asoc->state & SCTP_STATE_WAS_ABORTED)) {
 					/*
 					 * we need to get out. Peer probably
 					 * aborted.
 					 */
 					sctp_m_freem(mm);
-					if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) {
+					if (asoc->state & SCTP_STATE_WAS_ABORTED) {
 						SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
 						error = ECONNRESET;
 					}
@@ -13278,12 +13295,12 @@ skip_preblock:
 				 * This is ugly but we must assure locking
 				 * order
 				 */
-				if (hold_tcblock == 0) {
+				if (!hold_tcblock) {
 					SCTP_TCB_LOCK(stcb);
-					hold_tcblock = 1;
+					hold_tcblock = true;
 				}
 				sctp_prune_prsctp(stcb, asoc, srcv, (int)sndlen);
-				inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+				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)
 					max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
 				else
@@ -13292,7 +13309,7 @@ skip_preblock:
 					continue;
 				}
 				SCTP_TCB_UNLOCK(stcb);
-				hold_tcblock = 0;
+				hold_tcblock = false;
 			}
 			/* wait for space now */
 			if (non_blocking) {
@@ -13306,9 +13323,9 @@ skip_preblock:
 			}
 			/* What about the INIT, send it maybe */
 			if (queue_only_for_init) {
-				if (hold_tcblock == 0) {
+				if (!hold_tcblock) {
 					SCTP_TCB_LOCK(stcb);
-					hold_tcblock = 1;
+					hold_tcblock = true;
 				}
 				if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
 					/* a collision took us forward? */
@@ -13332,11 +13349,11 @@ skip_preblock:
 				}
 				asoc->ifp_had_enobuf = 0;
 			}
-			un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
+			un_sent = asoc->total_output_queue_size - asoc->total_flight;
 			if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
-			    (stcb->asoc.total_flight > 0) &&
-			    (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
-			    (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) {
+			    (asoc->total_flight > 0) &&
+			    (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
+			    (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) {
 				/*-
 				 * Ok, Nagle is set on and we have data outstanding.
 				 * Don't send anything and let SACKs drive out the
@@ -13358,9 +13375,9 @@ skip_preblock:
 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
 				sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only,
 				    nagle_applies, un_sent);
-				sctp_misc_ints(SCTP_CWNDLOG_PRESEND, stcb->asoc.total_output_queue_size,
-				    stcb->asoc.total_flight,
-				    stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count);
+				sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size,
+				    asoc->total_flight,
+				    asoc->chunks_on_out_queue, asoc->total_flight_count);
 			}
 			if (queue_only_for_init)
 				queue_only_for_init = 0;
@@ -13373,9 +13390,9 @@ skip_preblock:
 				 * and I don't need to start output :-D
 				 */
 				NET_EPOCH_ENTER(et);
-				if (hold_tcblock == 0) {
+				if (!hold_tcblock) {
 					if (SCTP_TCB_TRYLOCK(stcb)) {
-						hold_tcblock = 1;
+						hold_tcblock = true;
 						sctp_chunk_output(inp,
 						    stcb,
 						    SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
@@ -13387,9 +13404,9 @@ skip_preblock:
 				}
 				NET_EPOCH_EXIT(et);
 			}
-			if (hold_tcblock == 1) {
+			if (hold_tcblock) {
 				SCTP_TCB_UNLOCK(stcb);
-				hold_tcblock = 0;
+				hold_tcblock = false;
 			}
 			SOCKBUF_LOCK(&so->so_snd);
 			/*-
@@ -13406,7 +13423,7 @@ skip_preblock:
 			 * size we KNOW we will get to sleep safely with the
 			 * wakeup flag in place.
 			 */
-			inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+			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 +
 			    min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) {
 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
@@ -13428,8 +13445,8 @@ skip_preblock:
 					}
 					SOCKBUF_UNLOCK(&so->so_snd);
 					SCTP_TCB_SEND_LOCK(stcb);
-					if (((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
-					    ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) == 0) &&
+					if (((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
+					    ((asoc->state & SCTP_STATE_WAS_ABORTED) == 0) &&
 					    (sp != NULL)) {
 						sp->processing = 0;
 					}
@@ -13439,28 +13456,28 @@ skip_preblock:
 
 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
 					sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK,
-					    asoc, stcb->asoc.total_output_queue_size);
+					    asoc, asoc->total_output_queue_size);
 				}
 			}
 			SOCKBUF_UNLOCK(&so->so_snd);
 			SCTP_TCB_SEND_LOCK(stcb);
-			if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
-			    (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+			if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+			    (asoc->state & SCTP_STATE_WAS_ABORTED)) {
 				SCTP_TCB_SEND_UNLOCK(stcb);
 				goto out_unlocked;
 			}
 			SCTP_TCB_SEND_UNLOCK(stcb);
 		}
 		SCTP_TCB_SEND_LOCK(stcb);
-		if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
-		    (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+		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) {
 			if (sp->msg_is_complete == 0) {
 				strm->last_msg_incomplete = 1;
-				if (stcb->asoc.idata_supported == 0) {
+				if (asoc->idata_supported == 0) {
 					asoc->stream_locked = 1;
 					asoc->stream_locked_on = srcv->sinfo_stream;
 				}
@@ -13479,27 +13496,34 @@ skip_preblock:
 		if (uio->uio_resid == 0) {
 			got_all_of_the_send = 1;
 		}
+		if (!hold_tcblock) {
+			SCTP_TCB_LOCK(stcb);
+			hold_tcblock = true;
+		}
 	} else {
-		/* We send in a 0, since we do NOT have any locks */
-		error = sctp_msg_append(stcb, net, top, srcv, 0);
+		/* We send in a 1, since we do have the stcb lock. */
+		error = sctp_msg_append(stcb, net, top, srcv, 1);
 		top = NULL;
 		if (sinfo_flags & SCTP_EOF) {
 			got_all_of_the_send = 1;
 		}
 	}
-	if (error) {
+	if (error != 0) {
 		goto out;
 	}
 dataless_eof:
+
+	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"));
+
 	/* EOF thing ? */
 	if ((sinfo_flags & SCTP_EOF) &&
 	    (got_all_of_the_send == 1)) {
 		SCTP_STAT_INCR(sctps_sends_with_eof);
 		error = 0;
-		if (hold_tcblock == 0) {
-			SCTP_TCB_LOCK(stcb);
-			hold_tcblock = 1;
-		}
 		if (TAILQ_EMPTY(&asoc->send_queue) &&
 		    TAILQ_EMPTY(&asoc->sent_queue) &&
 		    sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) {
@@ -13518,10 +13542,10 @@ dataless_eof:
 				}
 				SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
 				sctp_stop_timers_for_shutdown(stcb);
-				if (stcb->asoc.alternate) {
-					netp = stcb->asoc.alternate;
+				if (asoc->alternate != NULL) {
+					netp = asoc->alternate;
 				} else {
-					netp = stcb->asoc.primary_destination;
+					netp = asoc->primary_destination;
 				}
 				sctp_send_shutdown(stcb, netp);
 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
@@ -13543,10 +13567,6 @@ dataless_eof:
 			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)) {
-				if (hold_tcblock == 0) {
-					SCTP_TCB_LOCK(stcb);
-					hold_tcblock = 1;
-				}
 				if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
 					SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
 				}
@@ -13559,8 +13579,8 @@ dataless_eof:
 
 			abort_anyway:
 					if (free_cnt_applied) {
-						atomic_subtract_int(&stcb->asoc.refcnt, 1);
-						free_cnt_applied = 0;
+						atomic_subtract_int(&asoc->refcnt, 1);
+						free_cnt_applied = false;
 					}
 					SCTP_SNPRINTF(msg, sizeof(msg),
 					    "%s:%d at %s", __FILE__, __LINE__, __func__);
@@ -13570,11 +13590,7 @@ dataless_eof:
 					sctp_abort_an_association(stcb->sctp_ep, stcb,
 					    op_err, false, SCTP_SO_LOCKED);
 					NET_EPOCH_EXIT(et);
-					/*
-					 * now relock the stcb so everything
-					 * is sane
-					 */
-					hold_tcblock = 0;
+					hold_tcblock = false;
 					stcb = NULL;
 					goto out;
 				}
@@ -13585,14 +13601,16 @@ dataless_eof:
 		}
 	}
 skip_out_eof:
-	if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
+	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"));
+
+	if (!TAILQ_EMPTY(&asoc->control_send_queue)) {
 		some_on_control = 1;
 	}
 	if (queue_only_for_init) {
-		if (hold_tcblock == 0) {
-			SCTP_TCB_LOCK(stcb);
-			hold_tcblock = 1;
-		}
 		if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
 			/* a collision took us forward? */
 			queue_only = 0;
@@ -13605,7 +13623,7 @@ skip_out_eof:
 		}
 	}
 	if ((net->flight_size > net->cwnd) &&
-	    (stcb->asoc.sctp_cmt_on_off == 0)) {
+	    (asoc->sctp_cmt_on_off == 0)) {
 		SCTP_STAT_INCR(sctps_send_cwnd_avoid);
 		queue_only = 1;
 	} else if (asoc->ifp_had_enobuf) {
@@ -13615,11 +13633,11 @@ skip_out_eof:
 		}
 		asoc->ifp_had_enobuf = 0;
 	}
-	un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
+	un_sent = asoc->total_output_queue_size - asoc->total_flight;
 	if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
-	    (stcb->asoc.total_flight > 0) &&
-	    (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
-	    (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) {
+	    (asoc->total_flight > 0) &&
+	    (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
+	    (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) {
 		/*-
 		 * Ok, Nagle is set on and we have data outstanding.
 		 * Don't send anything and let SACKs drive out the
@@ -13641,82 +13659,67 @@ skip_out_eof:
 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
 		sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only,
 		    nagle_applies, un_sent);
-		sctp_misc_ints(SCTP_CWNDLOG_PRESEND, stcb->asoc.total_output_queue_size,
-		    stcb->asoc.total_flight,
-		    stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count);
+		sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size,
+		    asoc->total_flight,
+		    asoc->chunks_on_out_queue, asoc->total_flight_count);
 	}
 	NET_EPOCH_ENTER(et);
-	if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) {
-		/* we can attempt to send too. */
-		if (hold_tcblock == 0) {
-			/*
-			 * If there is activity recv'ing sacks no need to
-			 * send
-			 */
-			if (SCTP_TCB_TRYLOCK(stcb)) {
-				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
-				hold_tcblock = 1;
-			}
-		} else {
-			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
-		}
+	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);
 	} else if ((queue_only == 0) &&
-		    (stcb->asoc.peers_rwnd == 0) &&
-	    (stcb->asoc.total_flight == 0)) {
+		    (asoc->peers_rwnd == 0) &&
+	    (asoc->total_flight == 0)) {
 		/* We get to have a probe outstanding */
-		if (hold_tcblock == 0) {
-			hold_tcblock = 1;
-			SCTP_TCB_LOCK(stcb);
-		}
 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
 	} else if (some_on_control) {
 		int num_out, reason;
 
 		/* Here we do control only */
-		if (hold_tcblock == 0) {
-			hold_tcblock = 1;
-			SCTP_TCB_LOCK(stcb);
-		}
-		(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
+		(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out,
 		    &reason, 1, 1, &now, &now_filled,
 		    sctp_get_frag_point(stcb),
 		    SCTP_SO_LOCKED);
 	}
 	NET_EPOCH_EXIT(et);
 	SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n",
-	    queue_only, stcb->asoc.peers_rwnd, un_sent,
-	    stcb->asoc.total_flight, stcb->asoc.chunks_on_out_queue,
-	    stcb->asoc.total_output_queue_size, error);
+	    queue_only, asoc->peers_rwnd, un_sent,
+	    asoc->total_flight, asoc->chunks_on_out_queue,
+	    asoc->total_output_queue_size, error);
+
+	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"));
 
*** 45 LINES SKIPPED ***