summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c314
1 files changed, 266 insertions, 48 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 715cc4d..31b9c06 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1277,7 +1277,7 @@ select_a_new_ep:
* first I must verify that this won't effect things :-0
*/
if (it->no_chunk_output == 0)
- sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
SCTP_TCB_UNLOCK(it->stcb);
next_assoc:
@@ -1391,10 +1391,14 @@ sctp_timeout_handler(void *t)
struct sctp_tcb *stcb;
struct sctp_nets *net;
struct sctp_timer *tmr;
+
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
int did_output;
struct sctp_iterator *it = NULL;
-
tmr = (struct sctp_timer *)t;
inp = (struct sctp_inpcb *)tmr->ep;
stcb = (struct sctp_tcb *)tmr->tcb;
@@ -1547,7 +1551,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
if ((stcb->asoc.num_send_timers_up == 0) &&
(stcb->asoc.sent_queue_cnt > 0)
) {
@@ -1592,7 +1596,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_SHUTDOWN:
if ((stcb == NULL) || (inp == NULL)) {
@@ -1607,7 +1611,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
{
@@ -1637,7 +1641,7 @@ sctp_timeout_handler(void *t)
#endif
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
stcb->sctp_ep, stcb, lnet);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
}
break;
case SCTP_TIMER_TYPE_COOKIE:
@@ -1657,7 +1661,7 @@ sctp_timeout_handler(void *t)
* We consider T3 and Cookie timer pretty much the same with
* respect to where from in chunk_output.
*/
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_NEWCOOKIE:
{
@@ -1709,7 +1713,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
if ((stcb == NULL) || (inp == NULL)) {
@@ -1717,7 +1721,7 @@ sctp_timeout_handler(void *t)
}
SCTP_STAT_INCR(sctps_timoshutdownguard);
sctp_abort_an_association(inp, stcb,
- SCTP_SHUTDOWN_GUARD_EXPIRES, NULL);
+ SCTP_SHUTDOWN_GUARD_EXPIRES, NULL, SCTP_SO_NOT_LOCKED);
/* no need to unlock on tcb its gone */
goto out_decr;
@@ -1730,7 +1734,7 @@ sctp_timeout_handler(void *t)
goto out_decr;
}
SCTP_STAT_INCR(sctps_timostrmrst);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_EARLYFR:
/* Need to do FR of things for net */
@@ -1752,7 +1756,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_AUTOCLOSE:
@@ -1761,7 +1765,7 @@ sctp_timeout_handler(void *t)
}
SCTP_STAT_INCR(sctps_timoautoclose);
sctp_autoclose_timer(inp, stcb, net);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
did_output = 0;
break;
case SCTP_TIMER_TYPE_ASOCKILL:
@@ -1772,7 +1776,18 @@ sctp_timeout_handler(void *t)
/* Can we free it yet? */
SCTP_INP_DECR_REF(inp);
sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(inp);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
/*
* free asoc, always unlocks (or destroy's) so prevent
* duplicate unlock or unlock of a free mtx :-0
@@ -2829,12 +2844,21 @@ int sctp_asoc_change_wake = 0;
static void
sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
- uint32_t error, void *data)
+ uint32_t error, void *data, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_assoc_change *sac;
struct sctp_queued_to_read *control;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
/*
* First if we are are going down dump everything we can to the
* socket rcv queue.
@@ -2863,8 +2887,27 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
stcb->sctp_socket->so_error = ECONNRESET;
}
/* Wake ANY sleepers */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sorwakeup(stcb->sctp_socket);
sowwakeup(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
sctp_asoc_change_wake++;
}
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
@@ -2903,10 +2946,29 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, so_locked);
if (event == SCTP_COMM_LOST) {
/* Wake up any sleeper */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
}
@@ -2970,13 +3032,17 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
static void
sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
- struct sctp_tmit_chunk *chk)
+ struct sctp_tmit_chunk *chk, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
@@ -3036,13 +3102,17 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, so_locked);
}
static void
sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
- struct sctp_stream_queue_pending *sp)
+ struct sctp_stream_queue_pending *sp, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
@@ -3102,7 +3172,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, so_locked);
}
@@ -3149,7 +3219,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
/* This always must be called with the read-queue LOCKED in the INP */
@@ -3242,7 +3312,24 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/* mark socket closed for read/write and wakeup! */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
socantsendmore(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
/* event not enabled */
@@ -3276,7 +3363,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
static void
@@ -3344,13 +3431,17 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
void
sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
- uint32_t error, void *data)
+ uint32_t error, void *data, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
if (stcb == NULL) {
/* unlikely but */
@@ -3379,7 +3470,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
switch (notification) {
case SCTP_NOTIFY_ASSOC_UP:
if (stcb->asoc.assoc_up_sent == 0) {
- sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, so_locked);
stcb->asoc.assoc_up_sent = 1;
}
if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
@@ -3387,7 +3478,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
break;
case SCTP_NOTIFY_ASSOC_DOWN:
- sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, so_locked);
break;
case SCTP_NOTIFY_INTERFACE_DOWN:
{
@@ -3418,11 +3509,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
case SCTP_NOTIFY_SPECIAL_SP_FAIL:
sctp_notify_send_failed2(stcb, error,
- (struct sctp_stream_queue_pending *)data);
+ (struct sctp_stream_queue_pending *)data, so_locked);
break;
case SCTP_NOTIFY_DG_FAIL:
sctp_notify_send_failed(stcb, error,
- (struct sctp_tmit_chunk *)data);
+ (struct sctp_tmit_chunk *)data, so_locked);
break;
case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
{
@@ -3438,9 +3529,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_ASSOC_ABORTED:
if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) {
- sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, NULL, so_locked);
} else {
- sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, NULL, so_locked);
}
break;
case SCTP_NOTIFY_PEER_OPENED_STREAM:
@@ -3448,7 +3539,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_STREAM_OPENED_OK:
break;
case SCTP_NOTIFY_ASSOC_RESTART:
- sctp_notify_assoc_change(SCTP_RESTART, stcb, error, data);
+ sctp_notify_assoc_change(SCTP_RESTART, stcb, error, data, so_locked);
break;
case SCTP_NOTIFY_HB_RESP:
break;
@@ -3505,7 +3596,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
void
-sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
+sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct sctp_association *asoc;
struct sctp_stream_out *outs;
@@ -3546,7 +3641,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
}
sctp_free_bufspace(stcb, asoc, chk, 1);
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_SENT, chk);
+ SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
@@ -3574,7 +3669,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
}
}
sctp_free_bufspace(stcb, asoc, chk, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
+ sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
@@ -3595,7 +3690,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
TAILQ_REMOVE(&outs->outqueue, sp, next);
sctp_free_spbufspace(stcb, asoc, sp);
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp);
+ SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp, so_locked);
if (sp->data) {
sctp_m_freem(sp->data);
sp->data = NULL;
@@ -3616,7 +3711,11 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
}
void
-sctp_abort_notification(struct sctp_tcb *stcb, int error)
+sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
if (stcb == NULL) {
@@ -3628,13 +3727,13 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error)
return;
}
/* Tell them we lost the asoc */
- sctp_report_all_outbound(stcb, 1);
+ sctp_report_all_outbound(stcb, 1, so_locked);
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))) {
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
}
- sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL);
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL, so_locked);
}
void
@@ -3644,11 +3743,16 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
{
uint32_t vtag;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
vtag = 0;
if (stcb != NULL) {
/* We have a TCB to abort, send notification too */
vtag = stcb->asoc.peer_vtag;
- sctp_abort_notification(stcb, 0);
+ sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED);
/* get the assoc vrf id and table id */
vrf_id = stcb->asoc.vrf_id;
stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
@@ -3656,7 +3760,18 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id);
if (stcb != NULL) {
/* Ok, now lets free it */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(inp);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
} else {
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
@@ -3733,10 +3848,23 @@ none_in:
void
sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- int error, struct mbuf *op_err)
+ int error, struct mbuf *op_err,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
uint32_t vtag;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(inp);
+#endif
if (stcb == NULL) {
/* Got to have a TCB */
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
@@ -3752,9 +3880,9 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
vtag = stcb->asoc.peer_vtag;
/* notify the ulp */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)
- sctp_abort_notification(stcb, error);
+ sctp_abort_notification(stcb, error, so_locked);
/* notify the peer */
- sctp_send_abort_tcb(stcb, op_err);
+ sctp_send_abort_tcb(stcb, op_err, so_locked);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -3764,7 +3892,21 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ }
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
void
@@ -4105,7 +4247,12 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_queued_to_read *control,
struct sockbuf *sb,
- int end)
+ int end,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*
* Here we must place the control on the end of the socket read
@@ -4172,8 +4319,30 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
if (inp && inp->sctp_socket) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
- } else
+ } else {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(inp);
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sctp_sorwakeup(inp, inp->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
+ }
}
}
@@ -4296,8 +4465,26 @@ get_out:
if (inp && inp->sctp_socket) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
- } else
+ } else {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(inp);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (0);
+ }
+#endif
sctp_sorwakeup(inp, inp->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ }
}
return (0);
}
@@ -4367,7 +4554,11 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
- int reason, struct sctpchunk_listhead *queue)
+ int reason, struct sctpchunk_listhead *queue, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
int ret_sz = 0;
int notdone;
@@ -4377,11 +4568,38 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
ret_sz += tp1->book_size;
tp1->sent = SCTP_FORWARD_TSN_SKIP;
if (tp1->data) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1);
+ sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, SCTP_SO_NOT_LOCKED);
sctp_m_freem(tp1->data);
tp1->data = NULL;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /*
+ * assoc was freed while we were
+ * unlocked
+ */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (ret_sz);
+ }
+ }
+#endif
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
stcb->asoc.sent_queue_cnt_removeable--;
@@ -4423,7 +4641,7 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
*/
if (tp1) {
ret_sz += sctp_release_pr_sctp_chunk(stcb, tp1, reason,
- &stcb->asoc.send_queue);
+ &stcb->asoc.send_queue, so_locked);
} else {
SCTP_PRINTF("hmm, nothing on the send queue and no EOM?\n");
}
@@ -4627,7 +4845,7 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock,
SCTP_STAT_INCR(sctps_wu_sacks_sent);
sctp_send_sack(stcb);
sctp_chunk_output(stcb->sctp_ep, stcb,
- SCTP_OUTPUT_FROM_USR_RCVD);
+ SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
/* make sure no timer is running */
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_6);
SCTP_TCB_UNLOCK(stcb);
OpenPOWER on IntegriCloud