summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r--sys/netinet/sctp_output.c110
1 files changed, 70 insertions, 40 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 28b39d1..3b60f85 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3270,7 +3270,12 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
int nofragment_flag,
int ecn_ok,
struct sctp_tmit_chunk *chk,
- int out_of_asoc_ok)
+ int out_of_asoc_ok,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
{
/*
@@ -3456,7 +3461,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb,
SCTP_FAILED_THRESHOLD,
- (void *)net);
+ (void *)net,
+ so_locked);
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
@@ -3840,7 +3846,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
void
-sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
+sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m, *m_at, *mp_last;
struct sctp_nets *net;
@@ -4108,7 +4118,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n");
ret = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- m, 0, NULL, 0, 0, NULL, 0);
+ m, 0, NULL, 0, 0, NULL, 0, so_locked);
SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
@@ -5169,7 +5179,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
p_len += padval;
}
(void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
- NULL, 0);
+ NULL, 0, SCTP_SO_NOT_LOCKED);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -5279,7 +5289,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
cause = SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_UNSENT;
ret_spc = sctp_release_pr_sctp_chunk(stcb, chk,
cause,
- &asoc->sent_queue);
+ &asoc->sent_queue, SCTP_SO_LOCKED);
freed_spc += ret_spc;
if (freed_spc >= dataout) {
return;
@@ -5304,7 +5314,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
ret_spc = sctp_release_pr_sctp_chunk(stcb, chk,
SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_UNSENT,
- &asoc->send_queue);
+ &asoc->send_queue, SCTP_SO_LOCKED);
freed_spc += ret_spc;
if (freed_spc >= dataout) {
@@ -5670,7 +5680,11 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int *num_out,
int *reason_code,
int control_only, int *cwnd_full, int from_where,
- struct timeval *now, int *now_filled, int frag_point);
+ struct timeval *now, int *now_filled, int frag_point, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
static void
sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
@@ -5720,7 +5734,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(inp, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- m);
+ m, SCTP_SO_NOT_LOCKED);
/*
* sctp_abort_an_association calls sctp_free_asoc()
* free association will NOT free it since we
@@ -5814,7 +5828,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- NULL);
+ NULL, SCTP_SO_NOT_LOCKED);
atomic_add_int(&stcb->asoc.refcnt, -1);
goto no_chunk_output;
}
@@ -5835,7 +5849,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
do_chunk_output = 0;
}
if (do_chunk_output)
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED);
else if (added_control) {
int num_out = 0, reason = 0, cwnd_full = 0, now_filled = 0;
struct timeval now;
@@ -5843,7 +5857,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
frag_point = sctp_get_frag_point(stcb, &stcb->asoc);
(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
- &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point);
+ &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point, SCTP_SO_NOT_LOCKED);
}
no_chunk_output:
if (ret) {
@@ -6858,7 +6872,11 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int *num_out,
int *reason_code,
int control_only, int *cwnd_full, int from_where,
- struct timeval *now, int *now_filled, int frag_point)
+ struct timeval *now, int *now_filled, int frag_point, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*
* Ok this is the generic chunk service queue. we must do the
@@ -7268,7 +7286,7 @@ again_one_more_time:
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain, auth_offset, auth,
- no_fragmentflg, 0, NULL, asconf))) {
+ no_fragmentflg, 0, NULL, asconf, so_locked))) {
if (error == ENOBUFS) {
asoc->ifp_had_enobuf = 1;
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -7548,7 +7566,7 @@ again_one_more_time:
no_fragmentflg,
bundle_at,
data_list[0],
- asconf))) {
+ asconf, so_locked))) {
/* error, we could not output */
if (error == ENOBUFS) {
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -8110,7 +8128,11 @@ static int
sctp_chunk_retransmission(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_association *asoc,
- int *cnt_out, struct timeval *now, int *now_filled, int *fr_done)
+ int *cnt_out, struct timeval *now, int *now_filled, int *fr_done, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*-
* send out one MTU of retransmission. If fast_retransmit is
@@ -8223,7 +8245,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo,
(struct sockaddr *)&chk->whoTo->ro._l_addr, m, auth_offset,
- auth, no_fragmentflg, 0, NULL, asconf))) {
+ auth, no_fragmentflg, 0, NULL, asconf, so_locked))) {
SCTP_STAT_INCR(sctps_lowlevelerr);
return (error);
}
@@ -8272,7 +8294,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
chk->snd_count,
sctp_max_retran_chunk);
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_abort_an_association(stcb->sctp_ep, stcb, 0, NULL);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, 0, NULL, so_locked);
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (SCTP_RETRAN_EXIT);
@@ -8461,7 +8483,7 @@ one_chunk_around:
/* Now lets send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr, m, auth_offset,
- auth, no_fragmentflg, 0, NULL, asconf))) {
+ auth, no_fragmentflg, 0, NULL, asconf, so_locked))) {
/* error, we could not output */
SCTP_STAT_INCR(sctps_lowlevelerr);
return (error);
@@ -8620,7 +8642,12 @@ sctp_timer_validation(struct sctp_inpcb *inp,
void
sctp_chunk_output(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
- int from_where)
+ int from_where,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*-
* Ok this is the generic chunk service queue. we must do the
@@ -8686,12 +8713,12 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1,
&cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
return;
} else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) {
/* if its not from a HB then do it */
fr_done = 0;
- ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled, &fr_done);
+ ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled, &fr_done, so_locked);
if (fr_done) {
tot_frs++;
}
@@ -8711,7 +8738,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1,
&cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(8, inp, stcb, NULL);
#endif
@@ -8738,7 +8765,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
#endif
/* Push out any control */
(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, &cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
return;
}
if (tot_frs > asoc->max_burst) {
@@ -8811,7 +8838,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
do {
error = sctp_med_chunk_output(inp, stcb, asoc, &num_out,
&reason_code, 0, &cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
if (error) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Error %d was returned from med-c-op\n", error);
if (sctp_logging_level & SCTP_LOG_MAXBURST_ENABLE) {
@@ -9092,7 +9119,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
int num_dups = 0;
int space_req;
-
a_chk = NULL;
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -9354,7 +9380,11 @@ sctp_send_sack(struct sctp_tcb *stcb)
void
-sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
+sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_abort;
struct mbuf *m_out = NULL, *m_end = NULL;
@@ -9409,7 +9439,6 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
abort->ch.chunk_flags = 0;
abort->ch.chunk_length = htons(sizeof(*abort) + sz);
-
/* prepend and fill in the SCTP header */
SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT);
if (m_out == NULL) {
@@ -9426,7 +9455,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb,
stcb->asoc.primary_destination,
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
- m_out, auth_offset, auth, 1, 0, NULL, 0);
+ m_out, auth_offset, auth, 1, 0, NULL, 0, so_locked);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -9455,7 +9484,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg);
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- m_shutdown_comp, 0, NULL, 1, 0, NULL, 0);
+ m_shutdown_comp, 0, NULL, 1, 0, NULL, 0, SCTP_SO_NOT_LOCKED);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return;
}
@@ -10877,6 +10906,7 @@ sctp_lower_sosend(struct socket *so,
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, EFAULT);
@@ -11422,7 +11452,7 @@ sctp_lower_sosend(struct socket *so,
/* release this lock, otherwise we hang on ourselves */
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- mm);
+ mm, SCTP_SO_LOCKED);
/* now relock the stcb so everything is sane */
hold_tcblock = 0;
stcb = NULL;
@@ -11777,7 +11807,7 @@ sctp_lower_sosend(struct socket *so,
queue_only_for_init = 0;
queue_only = 0;
} else {
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT);
queue_only_for_init = 0;
queue_only = 1;
@@ -11797,12 +11827,12 @@ sctp_lower_sosend(struct socket *so,
hold_tcblock = 1;
sctp_chunk_output(inp,
stcb,
- SCTP_OUTPUT_FROM_USR_SEND);
+ SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
} else {
sctp_chunk_output(inp,
stcb,
- SCTP_OUTPUT_FROM_USR_SEND);
+ SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
if (hold_tcblock == 1) {
SCTP_TCB_UNLOCK(stcb);
@@ -11960,7 +11990,7 @@ dataless_eof:
}
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- NULL);
+ NULL, SCTP_SO_LOCKED);
/*
* now relock the stcb so everything
* is sane
@@ -12039,7 +12069,7 @@ skip_out_eof:
queue_only_for_init = 0;
queue_only = 0;
} else {
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
queue_only_for_init = 0;
queue_only = 1;
@@ -12053,11 +12083,11 @@ skip_out_eof:
* send
*/
if (SCTP_TCB_TRYLOCK(stcb)) {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ 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_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
} else if ((queue_only == 0) &&
(stcb->asoc.peers_rwnd == 0) &&
@@ -12067,7 +12097,7 @@ skip_out_eof:
hold_tcblock = 1;
SCTP_TCB_LOCK(stcb);
}
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
} else if (some_on_control) {
int num_out, reason, cwnd_full, frag_point;
@@ -12078,7 +12108,7 @@ skip_out_eof:
}
frag_point = sctp_get_frag_point(stcb, &stcb->asoc);
(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
- &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point);
+ &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED);
}
SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d",
queue_only, stcb->asoc.peers_rwnd, un_sent,
OpenPOWER on IntegriCloud