diff options
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 314 |
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); |