305 lines
10 KiB
Diff
305 lines
10 KiB
Diff
--- sys/netinet/sctp_input.c
|
|
+++ sys/netinet/sctp_input.c
|
|
@@ -839,7 +839,6 @@ sctp_handle_abort(struct sctp_abort_chunk *abort,
|
|
SCTP_TCB_LOCK(stcb);
|
|
atomic_subtract_int(&stcb->asoc.refcnt, 1);
|
|
#endif
|
|
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED);
|
|
(void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
|
|
SCTP_FROM_SCTP_INPUT + SCTP_LOC_8);
|
|
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
|
@@ -1989,7 +1988,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
|
/* send up all the data */
|
|
SCTP_TCB_SEND_LOCK(stcb);
|
|
|
|
- sctp_report_all_outbound(stcb, 0, 1, SCTP_SO_LOCKED);
|
|
+ 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;
|
|
#if defined(SCTP_DETAILED_STR_STATS)
|
|
--- sys/netinet/sctp_output.c
|
|
+++ sys/netinet/sctp_output.c
|
|
@@ -13159,11 +13159,10 @@ sctp_lower_sosend(struct socket *so,
|
|
error = EINVAL;
|
|
goto out;
|
|
}
|
|
- SCTP_TCB_SEND_UNLOCK(stcb);
|
|
-
|
|
strm = &stcb->asoc.strmout[srcv->sinfo_stream];
|
|
if (strm->last_msg_incomplete == 0) {
|
|
do_a_copy_in:
|
|
+ SCTP_TCB_SEND_UNLOCK(stcb);
|
|
sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error);
|
|
if (error) {
|
|
goto out;
|
|
@@ -13189,13 +13188,11 @@ sctp_lower_sosend(struct socket *so,
|
|
if (srcv->sinfo_flags & SCTP_UNORDERED) {
|
|
SCTP_STAT_INCR(sctps_sends_with_unord);
|
|
}
|
|
+ sp->processing = 1;
|
|
TAILQ_INSERT_TAIL(&strm->outqueue, sp, next);
|
|
stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp, 1);
|
|
- SCTP_TCB_SEND_UNLOCK(stcb);
|
|
} else {
|
|
- SCTP_TCB_SEND_LOCK(stcb);
|
|
sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead);
|
|
- SCTP_TCB_SEND_UNLOCK(stcb);
|
|
if (sp == NULL) {
|
|
/* ???? Huh ??? last msg is gone */
|
|
#ifdef INVARIANTS
|
|
@@ -13207,7 +13204,16 @@ sctp_lower_sosend(struct socket *so,
|
|
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);
|
|
+ error = EINVAL;
|
|
+ goto out;
|
|
+ } else {
|
|
+ sp->processing = 1;
|
|
+ }
|
|
}
|
|
+ SCTP_TCB_SEND_UNLOCK(stcb);
|
|
while (uio->uio_resid > 0) {
|
|
/* How much room do we have? */
|
|
struct mbuf *new_tail, *mm;
|
|
@@ -13232,20 +13238,29 @@ sctp_lower_sosend(struct socket *so,
|
|
if (mm) {
|
|
sctp_m_freem(mm);
|
|
}
|
|
+ SCTP_TCB_SEND_LOCK(stcb);
|
|
+ if (sp != NULL) {
|
|
+ sp->processing = 0;
|
|
+ }
|
|
+ SCTP_TCB_SEND_UNLOCK(stcb);
|
|
goto out;
|
|
}
|
|
/* Update the mbuf and count */
|
|
SCTP_TCB_SEND_LOCK(stcb);
|
|
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
|
+ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
|
|
+ (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
|
|
/*
|
|
* we need to get out. Peer probably
|
|
* aborted.
|
|
*/
|
|
sctp_m_freem(mm);
|
|
- if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED) {
|
|
+ if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) {
|
|
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
|
|
error = ECONNRESET;
|
|
}
|
|
+ if (sp != NULL) {
|
|
+ sp->processing = 0;
|
|
+ }
|
|
SCTP_TCB_SEND_UNLOCK(stcb);
|
|
goto out;
|
|
}
|
|
@@ -13305,6 +13320,11 @@ sctp_lower_sosend(struct socket *so,
|
|
/* 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);
|
|
goto skip_out_eof;
|
|
}
|
|
/* What about the INIT, send it maybe */
|
|
@@ -13428,6 +13448,11 @@ sctp_lower_sosend(struct socket *so,
|
|
}
|
|
}
|
|
SOCKBUF_UNLOCK(&so->so_snd);
|
|
+ SCTP_TCB_SEND_LOCK(stcb);
|
|
+ if (sp != NULL) {
|
|
+ sp->processing = 0;
|
|
+ }
|
|
+ SCTP_TCB_SEND_UNLOCK(stcb);
|
|
goto out_unlocked;
|
|
}
|
|
|
|
@@ -13437,12 +13462,19 @@ sctp_lower_sosend(struct socket *so,
|
|
}
|
|
}
|
|
SOCKBUF_UNLOCK(&so->so_snd);
|
|
+ SCTP_TCB_SEND_LOCK(stcb);
|
|
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
|
+ if (sp != NULL) {
|
|
+ sp->processing = 0;
|
|
+ }
|
|
+ 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) {
|
|
+ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
|
|
+ (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
|
|
SCTP_TCB_SEND_UNLOCK(stcb);
|
|
goto out_unlocked;
|
|
}
|
|
@@ -13458,6 +13490,7 @@ sctp_lower_sosend(struct socket *so,
|
|
strm->last_msg_incomplete = 0;
|
|
asoc->stream_locked = 0;
|
|
}
|
|
+ sp->processing = 0;
|
|
} else {
|
|
SCTP_PRINTF("Huh no sp TSNH?\n");
|
|
strm->last_msg_incomplete = 0;
|
|
--- sys/netinet/sctp_pcb.c
|
|
+++ sys/netinet/sctp_pcb.c
|
|
@@ -4722,6 +4722,7 @@ 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;
|
|
@@ -4756,6 +4757,7 @@ 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);
|
|
@@ -4853,6 +4855,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
|
SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
|
|
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
|
|
}
|
|
+ SCTP_TCB_SEND_UNLOCK(stcb);
|
|
SCTP_TCB_UNLOCK(stcb);
|
|
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
|
|
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE))
|
|
@@ -4886,10 +4889,12 @@ 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) ||
|
|
@@ -4938,6 +4943,7 @@ 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);
|
|
}
|
|
@@ -4981,7 +4987,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
|
* in case.
|
|
*/
|
|
/* anything on the wheel needs to be removed */
|
|
- SCTP_TCB_SEND_LOCK(stcb);
|
|
for (i = 0; i < asoc->streamoutcnt; i++) {
|
|
struct sctp_stream_out *outs;
|
|
|
|
@@ -5012,7 +5017,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
|
sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED);
|
|
}
|
|
}
|
|
- SCTP_TCB_SEND_UNLOCK(stcb);
|
|
/* sa_ignore FREED_MEMORY */
|
|
TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) {
|
|
TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp);
|
|
@@ -5214,6 +5218,7 @@ 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);
|
|
--- sys/netinet/sctp_structs.h
|
|
+++ sys/netinet/sctp_structs.h
|
|
@@ -535,6 +535,7 @@ struct sctp_stream_queue_pending {
|
|
uint8_t sender_all_done;
|
|
uint8_t put_last_out;
|
|
uint8_t discard_rest;
|
|
+ uint8_t processing;
|
|
};
|
|
|
|
/*
|
|
--- sys/netinet/sctputil.c
|
|
+++ sys/netinet/sctputil.c
|
|
@@ -3858,7 +3858,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
|
|
}
|
|
|
|
void
|
|
-sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked
|
|
+sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int so_locked
|
|
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
|
SCTP_UNUSED
|
|
#endif
|
|
@@ -3884,9 +3884,6 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
|
|
return;
|
|
}
|
|
/* now through all the gunk freeing chunks */
|
|
- if (holds_lock == 0) {
|
|
- SCTP_TCB_SEND_LOCK(stcb);
|
|
- }
|
|
/* sent queue SHOULD be empty */
|
|
TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
|
|
TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
|
|
@@ -3963,10 +3960,6 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
|
|
/* sa_ignore FREED_MEMORY */
|
|
}
|
|
}
|
|
-
|
|
- if (holds_lock == 0) {
|
|
- SCTP_TCB_SEND_UNLOCK(stcb);
|
|
- }
|
|
}
|
|
|
|
void
|
|
@@ -3990,8 +3983,11 @@ sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error
|
|
(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, 0, so_locked);
|
|
+ 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 {
|
|
@@ -4023,7 +4019,6 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
|
if (stcb != NULL) {
|
|
/* We have a TCB to abort, send notification too */
|
|
sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
|
|
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED);
|
|
/* Ok, now lets free it */
|
|
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
|
so = SCTP_INP_SO(inp);
|
|
@@ -4133,8 +4128,6 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
|
}
|
|
}
|
|
return;
|
|
- } else {
|
|
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED);
|
|
}
|
|
/* notify the peer */
|
|
sctp_send_abort_tcb(stcb, op_err, so_locked);
|
|
--- sys/netinet/sctputil.h
|
|
+++ sys/netinet/sctputil.h
|
|
@@ -163,7 +163,7 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
|
|
void sctp_stop_timers_for_shutdown(struct sctp_tcb *);
|
|
|
|
void
|
|
-sctp_report_all_outbound(struct sctp_tcb *, uint16_t, int, int
|
|
+sctp_report_all_outbound(struct sctp_tcb *, uint16_t, int
|
|
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
|
SCTP_UNUSED
|
|
#endif
|